黑马程序员——Java基础——多线程

多线程

概述

进程:是一个正在执行中的程序
每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者 叫一个控制单元
线程:是进程中的一个独立的控制单元,线程控制着进程的执行
一个进程中至少有一个线程
java vm(虚拟机) 启动的时候会有一个进程java.exe,该进程中至少有一个线程负责java程序的执行,且这个线程运行的代码存在于main方法中,这个线程称之为主线程
更细节说明虚拟机,jvm启动不止一个线程,还有负责垃圾回收机制的线程
多线程的意义:多线程的出现,可以让程序中的多部分代码同时执行

创建线程_继承Thread类

如何创建线程:
1. 继承Thread类;
2. 复写run();//将自定义的代码储存在run()中,方便线程调用
3. 调用线程的strat();//1. 启动线程 2. 调用run方法
多线程的特性:随机性
为什么要覆盖run():
Thread用于描述线程,该类定义了一个功能用于存储线程要运行的代码,该存储功能就是run()方法

public class Test1 {
    public static void main(String[] args){
        Demo d1 = new Demo("one+");
        d1.start();
        Demo d2 = new Demo("two++");
        d2.start();
    }
}
class Demo extends Thread{
    Demo(String name){
        System.out.println(name);
    }
    public void run (){
        for(int i = 0; i <= 60; i++ ){
            System.out.println(Thread.currentThread().getName() + "::" + i);
        }
    }
}
线程运行状态

被创建
运行:start()
冻结(睡眠、等待):sleep(time)、wait()、notify()
消亡:stop()、run()方法结束
临时(阻塞)状态:具备运行资格,但是没有执行权

获取线程对象以及名称

获取当前对象:static Thread currentThread()
获取线程名称:getName()
设置线程名称:setNmae()

创建线程_实现Runnable接口
  1. 实现Runnable接口
  2. 覆盖Runnable接口中的run()方法
    将线程要运行的代码存放在该run()方法中
  3. 通过Thread类建立对象
  4. 将Runnable接口的子类对象作为实际参数传递给Thread类的构造参数
  5. 调用Thread类的start()方法开启线程并调用Runnable接口子类的run()方法

实现方式和继承方式的区别
避免了单继承的局限性,在定义线程的时候建议使用实现方式
两种方法的区别:
继承Thread类:线程运行的代码存放在Thread子类run()方法中
实现Runnable接口:线程运行的代码存放在接口的子类的run()方法中

class Ticket implements Runnable{
    private int tick = 100;
    Object obj = new Object();
    public void run() {
        while(true){
            if(tick>0){
                synchronized(obj){
                    try{Thread.sleep(10);}catch(Exception e){}
                    System.out.println(Thread.currentThread().getName() + "sela:" + tick--);
                }
            }
        }
    }
}
public class SellTicketDemo1 {
    public static void main(String[] args){
        Ticket t = new Ticket();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
    }
}
多线程的安全问题:

问题原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完另一个线程参与进来执行,导致共享数据的错误
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完再执行过程中,其他线程不能参与执行
同步代码块:

synchronized(对象){
    需要被同步的代码
}

参数“对象”就如同锁,持有锁的线程可以在同步中执行
没有持有锁的线程,即使获取了CPU的执行权,也不能执行
同步的前提:
1. 必须要有两个以上的线程
2. 必须是多个线程使用同一个锁
必须保证在同步中有一个线程在运行
好处:解决了多线程的安全问题
弊端:每次都要判断锁,消耗资源
同步函数:
如何找到函数中的多线程同步问题:
1. 明确哪些代码是多线程运行代码
2. 明确共享数据
3. 明确多线程运行代码中哪些语句是操作共享数据的
同步代码块:

Object obj = new Object();
public void test(){
    synchronized(obj){
        System.out.println("xxxx");
    }
}

同步函数:(用synchronized来修饰函数即可)

public synchronized void test(){
    System.out.println("xxxx");
}

同步函数用的是哪一个锁:
函数需要被对象调用。那么函数都有一个所属对象引用
就是this,所以同步函数使用的锁是this
同步函数被静态修饰后,使用的锁是什么:
被静态修饰后,不在是this。静态进内存时,内存中没有本类对象,
但是一个顶有该类对应的字节码文件对象。类名.class 该对象的类型是class
静态的同步方法,使用的锁是该方法所在类的字节码文件对象 类名.class

多线程_单例设计模式-懒汉式

饿汉式

class Single{
    private static final Single s = new Single();
    private Single(){}
    //Instance实例
    public static Single getInstance(){
        return s;
    }
}

懒汉式(延迟加载单例设计模式示例)

class Single{
    private static Single s = null;
    private Single(){}
    /*  同步方法后效率会比较低效
    public static synchronized Single getInstance(){
        if(s == null){
            return s;
        }
    }
    */
    public static Single getInstance(){
        if(s == null){
            synchronized(Single.class){
            if(s == null)
                s = new Single();
            }
        }
    }
}

懒汉式和饿汉式有什么不同:
1. 懒汉式的特点在于延时加载
2. 懒汉式延时加载在多线程的时候会出现线程安全问题
3. 用同步代码块和同步方法都行,但是会稍微低效,用双重判断可解决效率问题
4. 加同步的时候使用的锁为该类所属的字节码对象

多线程_死锁

同步中嵌套同步,而锁却不同
死锁示例:

public class DeadLockTest {
    public static void main(String[] args){
        Thread t1 = new Thread(new Test(true));
        Thread t2 = new Thread(new Test(false));
        t1.start();
        t2.start();
    }
}
class Test implements Runnable{
    private boolean flag;
    Test(boolean flag){
        this.flag = flag;
    }
    public void run() {
        if(flag){
            synchronized(MyLock.locka){
                System.out.println("if locka");
                synchronized(MyLock.lockb){
                    System.out.println("if lockb");
                }
            }
        }else{
            synchronized(MyLock.lockb){
                System.out.println("else lockb");
                synchronized(MyLock.locka){
                    System.out.println("else lockb");
                }
            }
        }
    }
}
class MyLock{
    static Object locka = new Object();
    static Object lockb = new Object();
}
多线程间的通信

多个线程在操作同一个资源,但是操作的动作不同
等待唤醒机制:

public class InputOutputDemo {
    public static void main(String[] args){
        Res r = new Res();
        Input in = new Input(r);
        Output out = new Output(r);

        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);

        t1.start();
        t2.start();
    }
}
class Res{
    String name;
    String sex;
    boolean flag = false;
}
/*
* wait();
* notify();  
* notifyall();
* 都是用在同步中,因为要对持有监视器(锁)的线程操作
* 所以要使用在同步中,因为只有同步才具有锁*/
class Input implements Runnable{
    private Res r;
    Input(Res r){
        this.r = r;
    }
    public void run(){
        int x = 0;
        while(true){
            synchronized(r){
                if(r.flag)
                    try{r.wait();}catch(Exception e){}
                if(x == 0){
                    r.name = "mike";
                    r.sex = "man";
                }else{
                    r.name = "lili";
                    r.sex = "woman";
                }
                x = (x + 1) % 2;
                r.flag = true;
                r.notify();
            }
        }
    }
}
class Output implements Runnable{
    private Res r;
    Output(Res r){
        this.r = r;
    }
    public void run(){
        while(true){
            synchronized(r){
                if(!r.flag)
                    try{r.wait();}catch(Exception e){}
                System.out.println(r.name + "..." + r.sex);
                r.flag = false;
                r.notify();
            }
        }
    }
}

等待唤醒机制代码优化:

public class InputOutputDemo {
    public static void main(String[] args){
        Res r = new Res();
        new Thread(new Input(r)).start();
        new Thread(new Output(r)).start();
    }
}
class Res{
    private String name;
    private String sex;
    private boolean flag = false;
    public synchronized void set(String name, String sex){
        if(flag)
            try{this.wait();}catch(Exception e){}
        this.name = name;
        this.sex = sex;
        flag = true;
        notify();
    }
    public synchronized void out(){
        if(!flag)
            try{this.wait();}catch(Exception e){}
        System.out.println(name + "..." + sex); 
        flag = false;
        notify();
    }
}
class Input implements Runnable{
    private Res r;
    Input(Res r){
        this.r = r;
    }
    public void run(){
        int x = 0;
        while(true){        
            if(x == 0){
                r.set("milk", "man");
            }else{
                r.set("lili", "women");
            }
            x = (x + 1) % 2;
        }
    }
}
class Output implements Runnable{
    private Res r;
    Output(Res r){
        this.r = r;
    }
    public void run(){
        while(true){
            r.out();
        }
    }
}
生产者消费者:
public class ProducerConsumer {
    public static void main(String[] args){
        Resource r = new Resource();
        new Thread(new Producer(r)).start();
        new Thread(new Consumer(r)).start();
    }
}
class Resource{
    private String name;
    private int count = 1;
    private boolean flag = false;
    public synchronized void set(String name){
        while(flag)
            try{wait();}catch(Exception e){}
        this.name = name + ".." + count++;
        System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name);
        flag = true;
        this.notifyAll();
    }
    public synchronized void out(){
        while(!flag)
            try{wait();}catch(Exception e){}
        System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name);
        flag = false;
        this.notifyAll();
    }
}
class Producer implements Runnable{
    private Resource res;
    Producer(Resource res){
        this.res = res;
    }
    public void run() {
        while(true){
            res.set("++商品++");
        }
    }
}
class Consumer implements Runnable{
    private Resource res;
    Consumer(Resource res){
        this.res = res;
    }
    public void run() {
        while(true){
            res.out();
        }
    }
}

生产者消费者JDK1.5升级新特性版本(显式的锁机制):
将同步synchronized替换成现实Lock操作
将Object中的wait,notify,notifyAll,替换Condition对象
该对象可以通过Lock锁进行获取

public class ProducerConsumer {
    public static void main(String[] args){
        Resource r = new Resource();
        new Thread(new Producer(r)).start();
        new Thread(new Consumer(r)).start();
        new Thread(new Consumer(r)).start();
        new Thread(new Consumer(r)).start();
    }
}
class Resource{
    private String name;
    private int count = 1;
    private boolean flag = false;
    private Lock lock = new ReentrantLock();
    private Condition condition_pro = lock.newCondition();
    private Condition condition_con = lock.newCondition();

    public void set(String name) throws InterruptedException{
        lock.lock();
        try{
            while(flag)
                condition_pro.await();
            this.name = name + ".." + count++;
            System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name);
            flag = true;
            condition_con.signal();
        }finally{
            lock.unlock();
        }
    }
    public void out() throws InterruptedException{
        lock.lock();
        try{
            while(!flag)
                condition_con.await();
            System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name);
            flag = false;
            condition_pro.signal();
        }finally{
            lock.unlock();
        }
    }
}
class Producer implements Runnable{
    private Resource res;
    Producer(Resource res){
        this.res = res;
    }
    public void run() {
        while(true){
            try {
                res.set("++商品++");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Consumer implements Runnable{
    private Resource res;
    Consumer(Resource res){
        this.res = res;
    }
    public void run() {
        while(true){
            try {
                res.out();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
多线程_停止线程

stop()已经过时,只有一种run()方法结束
开启多线程,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,结束线程
Thread类中提供interrupt()方法,强制让给线程恢复到运行状态中来

public class StopThreadDemo {
    public static void main(String[] args){
        StopThread st = new StopThread();
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(st);
        t1.start();
        t2.start();

        int num = 0;
        while(true){
            if(num++ == 60){
                t1.interrupt();
                t2.interrupt();
                break;
            }
            System.out.println(Thread.currentThread().getName() + "......" + num);
        }
    }
}
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() + "...Exception");
                flag = false;
            }
            System.out.println(Thread.currentThread().getName() + "...run");
        }
    }
    public void changeFlag(){
        flag = false;
    }
}
多线程_守护线程
  1. 在线程启动前调用
  2. 当前台线程全部运行结束后,后台线程自动结束运行(Java虚拟机退出)
    setDeamon():
Thread t = new Thread(对象);
t.setDeamon();
t.start();
多线程_Join()方法

当A线程执行到了B线程的.join(),A线程就会等待,等B线程都执行完,A才会执行多线程_优先级 & yield()方法
setPriority(int newPriority);优先级一共10级,10级别最优先
MAX_PRIORITY 10级
MIN_PRIORITY 1级别
NORM_PRIORITY 5级别
Thread.yield();临时释放线程执行权,能达到所有线程平均运行效果

几种多线程的定义方式
public class TestThread {
    public static void main(String[] args){
        new Thread(){
            public void run(){
                for(int i=0; i<100; i++){
                    System.out.println(Thread.currentThread().getName() + "...." + i);
                }
            }
        }.start();

        Runnable r = new Runnable(){
            public void run(){
                for(int i=0; i<100; i++){
                    System.out.println(Thread.currentThread().getName() + "...." + i);
                }
            }
        };
        new Thread(r).start();

        for(int i=0; i<100; i++){
            System.out.println(Thread.currentThread().getName() + "...." + i);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值