zoukankan      html  css  js  c++  java
  • 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();暂停当前正在执行的线程对象,执行其他线程。

  • 相关阅读:
    多重背包POJ1276不要求恰好装满 poj1014多重背包恰好装满
    哈理工1053完全背包
    求最小公倍数与最大公约数的函数
    Bus Pass ZOJ 2913 BFS 最大中取最小的
    POJ 3624 charm bracelet 01背包 不要求装满
    HavelHakimi定理(判断一个序列是否可图)
    z0j1008Gnome Tetravex
    ZOJ 1136 Multiple BFS 取模 POJ 1465
    01背包 擎天柱 恰好装满 zjut(浙江工业大学OJ) 1355
    zoj 2412 水田灌溉,求连通分支个数
  • 原文地址:https://www.cnblogs.com/aisam/p/4276871.html
Copyright © 2011-2022 走看看