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

  • 相关阅读:
    第一章:计算机网络参考模型
    阿里云ECS hadoop+spark+zookeeper+hive code-server 集群搭建
    IDEA SSM+MAVEN+JWT 图书管理系统
    IDEA SSM后端框架入门
    code-server Command ' ' not found
    code-server scala error: object apache is not a member of package org
    下面给出一个child-parent的表格,要求挖掘其中的父子辈关系,给出祖孙辈关系的表格。
    现在有多个输入文件,每个文件中的每行内容均为一个整数。要求读取所有文件中的整数,进行升序排序后,输出到一个新的文件中,输出的数据格式为每行两个整数,第一个整数为第二个整数的排序位次,第二个整数为原待排列的整数。
    对于两个输入文件,即文件A 和文件B ,请编写MapReduce程序,对两个文件进行合并排除其中重复的内容,得到一个新的输出文件C。
    现有以下关系型数据库中的表(见表4-20表4-21和表4-22),要求将具转换为适合Hbase存储的表并插入数据。
  • 原文地址:https://www.cnblogs.com/aisam/p/4276871.html
Copyright © 2020-2023  润新知