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();
    }

}

 

posted @ 2017-04-27 09:31  DamonDr  阅读(264)  评论(0编辑  收藏  举报