JAVA 线程

1.run 方法与start方法的区别

(1)start方法:开启线程并执行run方法的代码

(2)run方法:仅仅是对象调用方法,而线程创建了,并没有运行。//单线程

例如:下面的代码

 1 public class MyThread  extends Thread{
 2 
 3     private  String name;
 4     public MyThread(String name) {
 5         this.name = name;
 6     }
 7     public void run() {
 8         for(int i =0 ; i<5; i++){
 9             System.out.println(name+"====="+i);
10         }
11     }
12 
13     
14     public static void main(String[] args) {//里面的代码并没有实现多线程,都是main线程执行 
15         MyThread t = new MyThread("one");
16         MyThread t2 = new MyThread("two");
17         t.run(); //t线程没有启动,是main线程跳到 MyThread的run方法中执行其中的代码,下同 
18         t2.run();
19         for(int i =0 ; i<5; i++){
20             System.out.println("main====="+i);
21         }
22         
23     }
24 }

输出结果:

one=====0
one=====1
one=====2
one=====3
one=====4
two=====0
two=====1
two=====2
two=====3
two=====4
main=====0
main=====1
main=====2
main=====3
main=====4

结论:如果需要实现多线程运行, 把t.run();t2.run();改为t.start();t2.start();

2.线程的运行状态的转换图

3.实现线程的两种方式:

(1)继承Thread类,重写run方法

(2)实现Runnable接口,实现run方法

4.两种方式的区别:

(1)实现Runnable接口的方式,可以避免java单继承的局限性,建议使用这种方式,而且这种方式可以资源共享(售票例子)

(2)继承Thread:线程代码封装在Thread子类的run代码中

        实现接口方式:线程代码封装在实现Runnable接口的子类的run方法中

5.线程同步方式有两种

(1)同步代码块,方式:synchronized(对象){需要同步的代码}

(2)同步函数:在非静态函数声明前面加入synchronized,这种方式使用的锁是this。如果在静态函数[static]面前用synchronized修改,同步的对象是:对函数的类名.class.即使用的锁是该方法所在类的字节码文件对象

PS:同步的方式都是对对象加锁,同步函数的方式是对当前对象加锁,同步代码块可以指定特定的对象加锁

6.如何分析线程安全的代码

(1)明确哪些代码是多线程运行代码

(2)明确共享数据

(3)明确多线程运行代码中哪些语句 是操作共享数据的

7.线程通讯:通过wait();notify();notifyAll();方法来实现

(1)都使用在同步中,因为要对持有监视器(锁)的线程操作

所以要使用在同步中,因为只有同步才具有锁

(2)为什么这些操作线程的方法要定义Object类中?

因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁,

只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。

不可以对不同锁中的线程进行唤醒,也就是说,等待和唤醒必须是同一个锁

而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中

8.生产者消费者问题

(1)共享资源代码

/**
 * 共享资源
 * @author lisheng90777
 *
 */
public class Resource {

    private int index = 1;//商品编号 
    private String name = null;//商品名称
    private boolean flag = false;//同步标志位 
    public synchronized void set(String name){
        while(flag){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.name = name+""+index++;
        System.out.println("生产者生产了"+this.name);
        flag =true;
        this.notifyAll();//如果只有一个生产者一个消费者,可以用notify,但是是多个消费者与多个生产者,必须到notifyAll();
    }
    public synchronized void out(){
        while(!flag){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("消费者消费----"+this.name);
        flag =false;
        this.notifyAll();
    }
}

(2)生产者代码

/**
 * 生产者
 * @author lisheng90777
 *
 */
public class Producer implements Runnable{
    private Resource res;
    public Producer(Resource res) {
        this.res = res;
    }
    
    @Override
    public void run() {
        while(true){
            res.set("土豆 ");
        }
    }
}

(3)消费者代码

/**
 * 消费者
 * @author lisheng90777
 *
 */
public class Consumer implements Runnable{
    private Resource res;
    public Consumer(Resource res) {
        this.res = res;
    }
    
    @Override
    public void run() {
        while(true){
            res.out();
        }
    }
}

(4)main函数测试代码

public class ProducerConsumerDemo {

	public static void main(String[] args) {
		Resource res = new Resource();//共享资源
		new Thread(new Producer(res)).start();//生产者线程1
		new Thread(new Producer(res)).start();//生产者线程2
		new Thread(new Consumer(res)).start();//消费者线程1
		new Thread(new Consumer(res)).start();//消费者线程2
	}
}

(5)测试结果【部分结果】

生产者生产了土豆 47110
消费者消费----土豆 47110
生产者生产了土豆 47111
消费者消费----土豆 47111
生产者生产了土豆 47112
消费者消费----土豆 47112
生产者生产了土豆 47113
消费者消费----土豆 47113
生产者生产了土豆 47114
消费者消费----土豆 47114
生产者生产了土豆 47115
消费者消费----土豆 47115

9.生产者消费者问题【升级版,利用JDK1.5Lock接口】

(1)只是改变共享资源的类Resource

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 共享资源:这个方式可以实现只是唤醒对方等待的线程,不需要把本方等待的线程也唤醒 
 * JDK1.5或者以上的版本 
 * @author lisheng90777
 *
 */
public class Resource {

    private int index = 1;//商品编号 
    private String name = null;//商品名称
    private boolean flag = false;//同步标志位 
    private Lock lock = new ReentrantLock();
    private Condition condition_producer = lock.newCondition();//生产者线程操作对象
    private Condition condition_consumer = lock.newCondition();//消费者线程操作对象 

    public  void set(String name){
        lock.lock();//加锁 
        try{
            while(flag){
                try {
                    condition_producer.await();//生产者线程等待 
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.name = name+""+index++;
            System.out.println("生产者生产了"+this.name);
            flag =true;
            condition_consumer.signal();//唤醒消费者队列的第一个 
        }
        finally{
            lock.unlock();
        }
    }
    public  void out(){
        lock.lock();
        try{
            while(!flag){
                try {
                    condition_consumer.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("消费者消费----"+this.name);
            flag =false;
            condition_producer.signal();//唤醒生产者线程队列的第一个 
        }finally{
            lock.unlock();//必须有try ,finally方式,目的是:如果try里面代码报错,finally里面一定执行,也就是一定需要释放锁
        }
    }
}

 10.终止线程的interrupt方法:强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。

(1)线程类

public class StopThread implements Runnable{
    private boolean flag = true;
    public synchronized void run() {
        while(flag){
            try{
                wait();
            }catch(InterruptedException e){
                System.out.println(Thread.currentThread().getName()+".....InterruptedException");
                flag = false;//利用标志来控制线程是否结束 
            }
            System.out.println(Thread.currentThread().getName()+".....run");
        }
    }
    
    public void changeFlag(){
        flag = false;
    }
    
}

(2)测试

 1 public class StopThreadDemo {
 2 
 3     public static void main(String[] args) {
 4         StopThread st = new StopThread();
 5         Thread t1 = new Thread(st);
 6         Thread t2 = new Thread(st);
 7         t1.start();
 8         t2.start();
 9         int num =0;
10         while(true){
11             if(num++ == 10){
12                 //st.changeFlag();//通过改变标志来结束线程,弊端:如果线程出于中断状态时,例如线程调用wait()方法
13                 t1.interrupt();//强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
14                 t2.interrupt();
15                 break;
16             }
17             System.out.println(Thread.currentThread().getName()+"-----------"+num);
18         }
19         System.out.println("======over");
20     }
21 }

(3)结果:

main-----------1
main-----------2
main-----------3
main-----------4
main-----------5
main-----------6
main-----------7
main-----------8
main-----------9
main-----------10
======over
Thread-1.....InterruptedException
Thread-1.....run
Thread-0.....InterruptedException
Thread-0.....run

11.守护线程:在上面代码StopThreadDemo类中 ,在t1.start();前面加上t1.setDaemon(true);t2.setDaemon(true);,这两句语句表示:这个两个线程是守护线程,属于后台线程,当其他线程都运行完后,这两个后台线程就会自动终止,java虚拟机退出。注意:这个两个方法必须在启动线程前调用,也就是在start方法前调用 。

12.join方法

(1)当A线程执行到了B线程的join方法时,A线程就会等待,等待B线程执行完,A才会执行

(2)join可以用来临时加入线程执行

(3)例子:

public class JoinMethod implements Runnable{
    public void run() {
        for(int i = 0; i<5; i++){
            System.out.println(Thread.currentThread().getName()+"线程正在执行-------"+i);
        }
    }
}
public class JoinDemo {

    public static void main(String[] args) {
        JoinMethod sm = new JoinMethod();
        Thread t1 = new Thread(sm);
        Thread t2 = new Thread(sm);
        t1.start();
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();
        for(int i = 0 ; i<5; i++){
            System.out.println("主线程main方法正在执行------------"+i);
        }
        System.out.println("main方法结束");
    }
}

Thread-0线程正在执行-------0
Thread-0线程正在执行-------1
Thread-0线程正在执行-------2
Thread-0线程正在执行-------3
Thread-0线程正在执行-------4
主线程main方法正在执行------------0
主线程main方法正在执行------------1
主线程main方法正在执行------------2
主线程main方法正在执行------------3
主线程main方法正在执行------------4
main方法结束
Thread-1线程正在执行-------0
Thread-1线程正在执行-------1
Thread-1线程正在执行-------2
Thread-1线程正在执行-------3
Thread-1线程正在执行-------4

13. yield()方法,例如:Thread.yield();暂停当前正在执行的线程对象,执行其他线程。

原文地址:https://www.cnblogs.com/aisam/p/4276871.html