您的位置:首页 > 编程语言 > Java开发

java多线程知识个人总结诶

2014-10-09 15:21 495 查看
第一部分:概要说明

多线程是操作系统中的重要的理论知识,关于进程和线程有以下几个重要的知识:

1)、一个运行的java进程至少包括两个线程,一个是主线程,一个是垃圾回收线程、

2)、线程是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享数据。

3)、多进程是操作系统中同时运行的多个程序;多线程:在同一个进程中同时运行的多个任务;

4)、一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个执行控制单元即多个线程,使之并发运行。

5)、多线程的的一个重要特征就是随机性,是因为CPU按照时间片切换处理各个线程导致的,

多线程的作用是提高程序的运行效率,但是正是因为多线程之间要强点CPU资源,就会导致

线程的同步和异步,死锁等等情况的出现,而这些东西正是多线程中需要了解的东西。

线程和进程的区别:

1)、进程有独立的进程空间,进程中的数据存放空间(堆空间和栈空间)是独立的。

2)、线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响的。

第二部分:多线程的实现

创建线程有两种方式:

第一种方式是该类继承Thread类,重写run方法,然后创建线程对象,通过线程对象,调用start方法就能够实现。

下面的例子:

public class MultiThread extends Thread{

private String name;

public MultiThread(String name) {

this.name = name;

}

public static void main(String[] args) {

MultiThread ta = new MultiThread("A线程");

MultiThread tb = new MultiThread("B线程");

ta.start();

tb.start();

}

//重写Thread里面的run方法

public void run() {

for(int i=0;i<10;i++){

System.out.println(name+":运行"+i);

}

}

}

继承Thread类并不提倡使用,因为一个类只能继承一个类,这样就限制了类的拓展。

第二种方法是实现Runnable接口,并实现接口中的run方法。

例如下面的例子:

public class MultiThreadByRunnable implements Runnable {

private String name;

public MultiThreadByRunnable(String name) {

this.name = name;

}

public static void main(String[] args) {

MultiThreadByRunnable ta = new MultiThreadByRunnable("A线程");

MultiThreadByRunnable tb = new MultiThreadByRunnable("B线程");

Thread t1 = new Thread(ta);

Thread t2 = new Thread(tb);

t1.start();

t2.start();

}

//重写Thread里面的run方法

public void run() {

for(int i=0;i<10;i++){

System.out.println(name+":运行"+i);

}

}

}

使用接口的方式,如要需要多线程的对象放入到Thread对象中。因为一个类能够实现多个接口这样就解决了

无法多继承的问题。

一般线程生命周期的五种状态

新建(new Thread)

当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动,也没有占用资源)。

例如:Thread t1=new Thread();

就绪(runnable)

线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。

例如:t1.start();

运行(running)

线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

死亡(dead)

当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。

线程终止分为:

自然终止:正常运行run()方法后终止。

异常终止:调用stop()方法让一个线程终止运行。

堵塞(blocked)

由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。

正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。

正在等待:调用wait()方法。(调用motify()方法回到就绪状态)

被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)

join方法:调用join方法的线程对象强制运行,或者说联合执行,该线程强制运行期间,

其他线程无法运行,必须等到该线程结束后其他线程才可以运行。

在run方法中调用:

for (int i = 0; i < 50; i++) {

System.out.println(Thread.currentThread().getName()+"正在运行!"+i);

if(i == 25){

try {

new Thread(new MyThreadDemo(),"wangwu").join();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

setDaemon方法

后台线程:处于后台运行,任务是为其他线程提供服务。也称为“守护线程”或“精灵线程”。JVM的垃圾回收就是典型的后台线程。

特点:若所有的前台线程都死亡,后台线程自动死亡。

设置后台线程:Thread对象setDaemon(true);

setDaemon(true)必须在start()调用前。否则出现IllegalThreadStateException异常;

前台线程创建的线程默认是前台线程;

判断是否是后台线程:使用Thread对象的isDaemon()方法;

并且当且仅当创建线程是后台线程时,新线程才是后台线程。

sleep方法:线程休眠,让执行的线程暂停一段时间,进入阻塞状态,放弃占用CPU资源。

sleep(long milllis) throws InterruptedException:毫秒

sleep(long millis,int nanos)throws InterruptedException:毫秒,纳秒

调用sleep()后,在指定时间段之内,该线程不会获得执行的机会。

控制线程之优先级

每个线程都有优先级,优先级的高低只和线程获得执行机会的次数多少有关。

并非线程优先级越高的就一定先执行,哪个线程的先运行取决于CPU的调度;

默认情况下main线程具有普通的优先级,而它创建的线程也具有普通优先级。

Thread对象的setPriority(int x)和getPriority()来设置和获得优先级。

MAX_PRIORITY : 值是10

MIN_PRIORITY : 值是1

NORM_PRIORITY : 值是5(主方法默认优先级)

yield方法线程礼让;

暂停当前正在执行的线程对象,并执行其他线程;

Thread的静态方法,可以是当前线程暂停,但是不会阻塞该线程,而是进入就绪状态。

所以完全有可能:某个线程调用了yield()之后,线程调度器又把他调度出来重新执行。

多线程的安全问题的三种办法:

使用同步代码块:将执行的代码放到synchronized(){}中,参数一般是线程的名称或者是this。

public void run() {

for(int i=0;i<10;i++){

synchronized (name) {

System.out.println(name+":运行"+i);

}

}

}

调用synchronized方法:

public synchronized void ticketSell() {

for (int i = 0; i < 100; i++) {

if (num > 0) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + "卖出了第"

+ num-- + "张票!");

}

}

}

}

使用同步锁:

class FinalThreadDemo2 implements Runnable {

private int num = 50;

private final ReentrantLock lock = new ReentrantLock();

@Override

public void run() {

for (int i = 0; i < 100; i++) {

ticketSell();

}

}

public void ticketSell() {

lock.lock();

try{

//for (int i = 0; i < 100; i++) {

if (num > 0) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + "卖出了第"

+ num-- + "张票!");

}

//}

}finally{

lock.unlock();

}

}

}

线程通信:

wait():让当前线程放弃监视器进入等待,直到其他线程调用同一个监视器并调用notify()或notifyAll()为止。

notify():唤醒在同一对象监听器中调用wait方法的第一个线程。

notifyAll():唤醒在同一对象监听器中调用wait方法的所有线程。

await():等价于同步监听器的wait()方法;

signal():等价于同步监听器的notify()方法;

signalAll():等价于同步监听器的notifyAll()方法;

多线程经典例子:生产者和消费者问题,

/*

例子:设置属性

容易出现的问题是:

名字和性别不对应!

线程通信,很好!

*/

package com.demo.thread;

class Person{

private String name;

private String sex;

private Boolean isimpty = Boolean.TRUE;//内存区为空!

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getSex() {

return sex;

}

public void setSex(String sex) {

this.sex = sex;

}

public void set(String name,String sex){

synchronized (this) {

while(!isimpty.equals(Boolean.TRUE)){//不为空的话等待消费者消费!

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

this.name = name;//为空的话生产者创造!

this.sex = sex;

isimpty = Boolean.FALSE;//创造结束后修改属性!

this.notifyAll();

}

}

public void get(){

synchronized (this) {

while(!isimpty.equals(Boolean.FALSE)){

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println("姓名"+getName()+ ", "+"性别"+getSex());

isimpty = Boolean.TRUE;

this.notifyAll();

}

}

}

class Producer implements Runnable{

private Person p;

public Producer(Person p) {

super();

this.p = p;

}

@Override

public void run() {

for (int i = 0; i < 100; i++) {

if( i % 2 == 0){

p.set("zhangsan", "男");

}else{

p.set("lisi", "女");

}

}

}

}

class Consumer implements Runnable{

private Person p;

public Consumer(Person p) {

super();

this.p = p;

}

@Override

public void run() {

for (int i = 0; i < 100; i++) {

p.get();

}

}

}

public class ThreadDemo6 {

public static void main(String[] args) {

Person p = new Person();

new Thread(new Producer(p)).start();

new Thread(new Consumer(p)).start();

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐