• Java学习之多线程


    多线程:

    (一)进程与线程

    进程特点

    并发与并行的区别:

           

    多线程编程的好处:

                        

    (二)多线程的建立

    1,通过继承Thread类,代码如下:

    class MyThread extends Thread {
        private static int K = 10;//类共享变量
        private int M=10;//成员共享变量
        MyThread(){
            super();
        }
        @Override
        public void run() {
            System.out.println("in MyThread run");
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "K:" + K--);
                System.out.println(Thread.currentThread().getName() + "M:" + M--);
            }
        }
    }
    public class ThreadDemo1 {
        public static void main(String[] args) {
           //多线程Thead方式1
            MyThread thread2 = new MyThread();
            new Thread(thread2,"t2").start();//此时成员变量被共享,静态也被共享,k和M的结果为-9
            new Thread(thread2,"t3").start();
          //多线程Thead方式1
            MyThread thread3=new MyThread();//此时静态类变量被共享,k为-9,M为0.
            thread2.start();
            thread3.start();
        }
    }

    2,通过实现Runnable接口(推荐),代码如下:

    public class ThreadDemo1 {
        public static void main(String[] args) {
             //RUNNABLE 方式2
            MyRunnable myRunnable = new MyRunnable();
            new Thread(myRunnable,"t1").start();//此时成员变量被共享,静态也被共享,K和M为-9
            //RUNNABLE 方式2
            new Thread(myRunnable,"t3").start();
            MyRunnable myRunnable1 = new MyRunnable();//此时成员变量不被共享,静态被共享,K为-9,M为0
            new Thread(myRunnable,"t1").start();
            new Thread(myRunnable1,"t3").start();
        }
    }
    class MyRunnable implements Runnable {
        private  static int K = 10;
        private  int M = 10;
        @Override
        public void run() {
            System.out.println("in MyRunnable run");
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + " K:" + (K--));
                System.out.println(Thread.currentThread().getName() + " M:" + (M--));
            }
        }
    }    

    3,通过实现Callable接口和Future包装来建立:

    import java.util.Random;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class CallableThread {
        public static void main(String[] args) {
            Callable<Integer> callable = new Callable<Integer>() {
                public Integer call() throws Exception {
                    return new Random().nextInt(100);
                }
            };
            FutureTask<Integer> future = new FutureTask<Integer>(callable);
            new Thread(future).start();
            try {
                Thread.sleep(5000);// 可能做一些事情
                System.out.println(future.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    
    }
    View Code

    三种建立多线程的优劣比较有:

        

    (三)线程的生命周期

    Java线程具有五中基本状态

    新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

    就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

    运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就     绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

    阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

    1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

    2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

    3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

    死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

     关键字:

    1. yield:该线程让出CPU,进入就绪状态
    2. join:该子线程优先执行,相当于方法调用,父线程进入IO阻塞状态
    3. sleep:该线程让出CPU,进入IO阻塞状态,不释放对象锁
    4. wait:同步锁下进行使用,该线程进入阻塞状态,释放对象锁
    5. notify:唤醒wait下的线程,进入同步阻塞状态
    6. synchronized:同步锁,未获得锁的线程进入同步阻塞状态

    (五),多线程同步(Thread Synchronized)

    线程同步即保证某个线程访问某个共享资源时,其他的线程需要wait,即有顺序性

    (六),多线程案例

    1,线程死锁案例:

    /*死锁:
            线程1:synchronized(o1) { Thread.sleep() synchronized(o2) }
            线程2:synchronized(o2) { Thread.sleep() synchronized(o1) }
            首先线程1执行,对o1加同步锁,其他线程无法访问,
            然后线程1睡眠,让出cpu,线程2执行,锁住o2
            线程1睡眠结束,继续执行,要对o2加同步锁,但被线程2占据,所以上不了锁,
            处于等待获得o2同步锁的状态,且线程1不能结束,释放不了o1对象。
            线程2睡眠结束,继续执行,要对o1加同步锁,但被线程1占据,所以上不了锁,
            处于等待获得o1同步锁的状态,且线程2不能结束,故释放不了o2
            故处于死锁状态。
            死锁经典问题:哲学家问题
            方法:加粗锁定对象*/
    public class DeadThread implements Runnable {
        private int flag=0;
        static Object object=new Object();//类变量,只有一份,每个实例共享
        static Object object1=new Object();//
        public void run(){
            if (flag==0){
                synchronized (object) {//释放object同步锁,需要等object1锁释放,
                    System.out.println(flag);
                    try {
                        Thread.sleep(40);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (object1) {
                        //System.out.println(flag);
                    }
                }
            }
            if (flag==1){
                synchronized (object1) {//释放object1同步锁,需要等object锁释放.两个线程互相等待中
                    System.out.println(flag);
                    try {
                        Thread.sleep(400);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (object) {
                        //System.out.println(flag);
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            DeadThread deadThread=new DeadThread();
            DeadThread deadThread1=new DeadThread();
            deadThread.flag=0;
            deadThread.flag=1;
            Thread thread=new Thread(deadThread);
            Thread thread1=new Thread(deadThread1);
            thread.start();
            thread1.start();
        }
    }

    2,多线程多态:

    public class ThreadTest {
    
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
                if (i == 30) {
                    Runnable myRunnable = new MyRunnable();
                    Thread thread = new MyThread(myRunnable);//输出的是MyThread中的Run方法,多态的体现
                    Thread thread1=new Thread(myRunnalbe);//输出myRunnable中run方法。
                    thread1.start();
                    thread.start();
                }
            }
        }
    }
    
    class MyRunnable implements Runnable {
        private int i = 0;
    
        @Override
        public void run() {
            System.out.println("in MyRunnable run");
            for (i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }
    }
    
    class MyThread extends Thread {
    
        private int i = 0;
        
        public MyThread(Runnable runnable){
            super(runnable);
        }
    
        @Override
        public void run() {
            System.out.println("in MyThread run");
            for (i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }
    }

    3,生产者消费者模型:

    public class ProducerConsumer {
        public static void main(String[] args) {
            SycnStack ss=new SycnStack();
            Runnable producer=new Producer(ss);
            Runnable consumer=new Consumer(ss);
            new Thread(producer,"p1").start();
            /*new Thread(producer,"p2").start();
            new Thread(producer,"p3").start();
            new Thread(producer,"p4").start();
            new Thread(producer,"p5").start();*/
            new Thread(consumer,"c1").start();
        }
    }
    class WoTo{
        int id;
        WoTo(int id){
            this.id=id;
        }
    
        @Override
        public String toString() {
            return "WOTO"+":"+id;
        }
    }
    class SycnStack{
        WoTo[] wotoArr=new WoTo[6];
        int index=0;
        public synchronized void push(WoTo woto){
            while (index==6){//wotoArr.length==6,当stack中满6个时,生产停止,需要消费者消费并notify生产者继续生产
                try {
                    System.out.println("full");//发生wait后,如果没有notify唤醒写在wait的方法不执行。
                    this.wait();
    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            wotoArr[index]=woto;
            index+=1;
            this.notifyAll();//生产往后通知消费者,主要是唤醒消费者来消费,如果多线程也会唤醒生产者,但唤醒后任然可能会进入wait中
    
        }
        public synchronized WoTo pop(){
            while (index==0){
                try {
                    System.out.println("null");
                    this.wait();
    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            index-=1;
            this.notifyAll();//消费完后通知生产者,唤醒生产者来生产,注释掉会进入死锁状态即,消费者等生产者生产,而生产者在wait中。
            return wotoArr[index];
    
    
        }
    }
    class Producer implements Runnable{
        SycnStack ss=null;
        Producer(SycnStack ss){
            this.ss=ss;
        }
        @Override
        public void run() {
            for (int i=0;i<20;i+=1){//一个线程最多生产20个馒头
                WoTo woto=new WoTo(i);
                ss.push(woto);
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+":produce:"+woto);
            }
        }
    }
    class Consumer implements Runnable{
        SycnStack ss=null;
        Consumer(SycnStack ss){
            this.ss=ss;
        }
    
        @Override
        public void run() {
            for(int i=0;i<20;i+=1){//一个消费者最多消费20个
                WoTo woto=ss.pop();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+":consuemer:"+woto);
            }
        }
    }

    4,笔试题1:

    public class SyncThread1 implements Runnable {
        int num=100;
        /*
        m1()和m2()都加了同步锁,执行流程显示调用run方法中的m1(),对num加同步锁,然后让出cpu,开始main线程
        调用m2方法,不能访问不能修改num,结束然后,输出num,然后让出cpu,继续执行m1()方法。sleep并不代表结束就能马上运行,处于就绪状态
        需抢占
         */
        synchronized void m1(){
            num=1000;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("num"+num);
        }
         synchronized void m2(){
    
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(num);
             num=2000;
            //System.out.println(num);
        }
        public void run(){
            m1();
        }
    
        public static void main(String[] args) {
            SyncThread1 syncThread1=new SyncThread1();
            Thread thread=new Thread(syncThread1);
            thread.start();//新开的线程,不和main线程共线程
            syncThread1.m2();//在main线程中,因为m2()加了同步锁,即对num加锁了,m2无法对num修改,即不执行,直接执行下面这个输出
            System.out.println(syncThread1.num);//main线程要等syncThread1.m2()执行完才执行
        }
    }

    5,哲学家问题:

    /*问题描述:一圆桌前坐着5位哲学家,两个人中间有一只筷子,桌子中央有面条。哲学家思考问题,
    当饿了的时候拿起左右两只筷子吃饭,必须拿到两只筷子才能吃饭。上述问题会产生死锁的情况,
    当5个哲学家都拿起自己右手边的筷子,准备拿左手边的筷子时产生死锁现象。
    解决办法:
    1、添加一个服务生,只有当经过服务生同意之后才能拿筷子,服务生负责避免死锁发生。
    2、每个哲学家必须确定自己左右手的筷子都可用的时候,才能同时拿起两只筷子进餐,吃完之后同时放下两只筷子。
    代码实现:实现第2种方案*/
    public class PhilosopherDemo {
        public static void main(String[] args) {
            Fork fork=new Fork();
            //五个philosopher都指向同一个fork,所以此时相当于成员变量被多个线程共享了
            Philosopher philosopher=new Philosopher(fork,0);
            Philosopher philosopher1=new Philosopher(fork,1);
            Philosopher philosopher2=new Philosopher(fork,2);
            Philosopher philosopher3=new Philosopher(fork,3);
            Philosopher philosopher4=new Philosopher(fork,4);
            new Thread(philosopher).start();
            new Thread(philosopher1).start();
            new Thread(philosopher2).start();
            new Thread(philosopher3).start();
            new Thread(philosopher4).start();
    
        }
    }
    class Philosopher implements Runnable{
        Fork fork=null;
        int id;
        Philosopher(Fork fork,int id){
            this.fork=fork;
            this.id=id;
        }
        @Override
        public void run() {
            while(true){
                think();
                fork.getFork(this);
                eat();
                fork.offFork(this);
            }
        }
        public void think(){
            try {
                System.out.println(id+"in thinking");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        public void eat(){
            try {
                System.out.println(id+"in eating");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    class Fork{
        boolean[] fork={false,false,false,false,false};//模拟五把叉
        public synchronized void getFork(Philosopher p){
            while(fork[p.id]||fork[(p.id+1)%5]){
                System.out.println("p:"+p.id+"waiting");
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            fork[p.id]=true;
            fork[(p.id+1)%5]=true;
            System.out.println("p:"+p.id+"getFork");
        }
        public synchronized void offFork(Philosopher p){
            fork[p.id]=false;
            fork[(p.id+1)%5]=false;
            System.out.println("p:"+p.id+"offFork");
            this.notifyAll();
        }
    
    }
  • 相关阅读:
    Deep Learning入门
    基本技能(一)
    NNCRF之NNSegmentation, NNPostagging, NNNameEntity
    word2vector 使用方法 计算语义相似度
    Berkeley parser使用方法
    zpar使用方法之Chinese Word Segmentation
    【delphi】delphi出现‘尚未调用CoInitialize’异常
    VS05 VS08 VS10 工程之间的转换
    odbc数据源for mysql
    【delphi】Delphi过程、函数传递参数的八种方式
  • 原文地址:https://www.cnblogs.com/ksWorld/p/6764284.html
Copyright © 2020-2023  润新知