首页 > 代码库 > java多线程

java多线程

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------Java实现多线程有两种方式1.继承Thread类public class MyThread extends Thread{    private String name;    public MyThread(String name) {        this.name = name;    }    public void run() {        for(int i=0;i<5;i++){            System.out.println(name+"运行,i="+i);        }    }    public static void main(String[] args) {        MyThread mt1 = new MyThread("线程A");        MyThread mt2 = new MyThread("线程B");        mt1.run();        mt2.run();    }}上面程序运行完A再运行B,并没有交替运行,此时线程并没有启动,启动线程需要调用Thread的start方法:public class MyThread extends Thread{    private String name;    public MyThread(String name) {        this.name = name;    }    public void run() {        for (int i = 0; i < 10; i++) {            System.out.println(name+"运行,i="+i);        }    }    public static void main(String[] args) {        MyThread mt1 = new MyThread("线程A");        MyThread mt2 = new MyThread("线程B");        mt1.start();        mt2.start();    }}在启动多线程的时候为什么必须调用start(),而不能调用run()呢?start()方法在Thread中的定义public synchronized void start() {        if (threadStatus != 0)            throw new IllegalThreadStateException();        ...            start0();        ...    }    private native void start0();以上代码可以发现start()方法被重复调用会报异常。此方法调用了start0();  此方法是调用了操作系统函数,多线程的实现需要依靠底层操作系统支持。2.实现Runnable接口和Thread类构造方法结合,来启动线程class MyThread implements Runnable{    private String name;    public MyThread(String name) {        this.name = name;    }    public void run() {        for (int i = 0; i < 50; i++) {            System.out.println(name+"运行,"+i);        }    }    public static void main(String[] args) {        MyThread mt1 = new MyThread("线程A");        MyThread mt2 = new MyThread("线程B");        Thread t1 = new Thread(mt1);        Thread t2 = new Thread(mt2);        t1.start();        t2.start();    }}Thread类和Runnable接口Thread类是Runnable接口的子类,但他没有完全实现Runnable接口中的run()方法,而是调用了Runnable接口的run方法,也就是说此方法是由Runnable接口的子类完成的,所以如果要通过继承Thread类完成多线程,则必须复写run()方法,以下为部分定义private Runnable target;public Thread(ThreadGroup group, String name) {    init(group, null, name, 0);}private void init(ThreadGroup g, Runnable target, String name,        long stackSize, AccessControlContext acc){    ...    this.target = target;    ...}public void run() {    if (target != null) {        target.run();    }}Thread类和Runnable接口的子类同时继承Runnable接口,之后将Runnable接口的子类实例放入Thread类中,这种操作模式和代理设计类似两者区别1.继承Thread类不能资源共享 class MyThread extends Thread{    private int ticket = 5;    public void run() {        for (int i = 0; i < 100; i++) {            if(ticket > 0){                System.out.println("卖票:ticket="+ticket--);            }        }    }    public static void main(String[] args) {        MyThread mt1 = new MyThread();        MyThread mt2 = new MyThread();        mt1.start();        mt2.start();    }}两个线程分别卖了各自的5张票class MyThread implements Runnable{    private int ticket = 5;    public void run() {        for (int i = 0; i < 100; i++) {            if(ticket > 0){                System.out.println("卖票:ticket="+ticket--);            }        }    }    public static void main(String[] args) {        MyThread mt = new MyThread();        new Thread(mt).start();        new Thread(mt).start();    }两个线程共卖了5张票总结:1.使用Runnable接口可以使多个线程共享同一资源         2. 避免单继承带来的局限线程的状态1.创建状态程序中使用构造方法创建了一个线程对象后,就有了相应的内存空间和其他资源,但还处于不可运行状态。2.就绪状态调用start()启动线程后就进入就绪状态,进入线程队列排队,等待cpu服务,已经具备运行条件3.运行状态当就绪状态的线程获得处理器资源时就进入了运行状态,自动调用run(),run()定义了线程的操作和功能4.阻塞状态当正在执行的线程,被人为挂起suspend(),sleep(),wait()或执行了耗时的I/O操作,会让出cpu并中止自己的执行,进入阻塞状态,不能进入排队队列,只有当引起阻塞的原因解除后,才能转入就绪状态5.死亡状态当调用stop()方法时和run()方法执行结束后,线程进入死亡状态,此时不具有继续运行的能力。线程操作的相关方法创建线程如果没有为线程指定一个名称,会自动为线程分配一个名称格式为:Thread-x。Thread类中有一个static类型的属性为线程自动命名。class MyThread implements Runnable{    // 实现Runnable接口    public void run(){    // 覆写run()方法        for(int i=0;i<3;i++){            System.out.println(Thread.currentThread().getName()                    + "运行,i = " + i) ;    // 取得当前线程的名字        }    }};public class CurrentThreadDemo{    public static void main(String args[]){        MyThread mt = new MyThread() ;    // 实例化Runnable子类对象        new Thread(mt,"线程").start() ;        // 启动线程        mt.run() ;    // 直接调用run()方法    }};运行结果main运行,i = 0线程运行,i = 0main运行,i = 1线程运行,i = 1main运行,i = 2线程运行,i = 2以上程序中,主方法直接通过Runnable接口的子类对象调用其中的run(),主方法也是一个线程,java中所有线程都是同时启动的,哪个线程先抢占到cpu资源,哪个就先执行。java程序每次运行至少执行2个进程,一个main进程,一个垃圾收集进程。判断线程是否启动class MyThread implements Runnable{    // 实现Runnable接口    public void run(){    // 覆写run()方法        for(int i=0;i<3;i++){            System.out.println(Thread.currentThread().getName()                    + "运行,i = " + i) ;    // 取得当前线程的名字        }    }};public class ThreadAliveDemo{    public static void main(String args[]){        MyThread mt = new MyThread() ;        // 实例化Runnable子类对象        Thread t = new Thread(mt,"线程");        // 实例化Thread对象        System.out.println("线程开始执行之前 --> " + t.isAlive()) ;     // 判断是否启动        t.start() ;    // 启动线程        System.out.println("线程开始执行之后 --> " + t.isAlive()) ;     // 判断是否启动        for(int i=0;i<3;i++){            System.out.println("main运行 --> " + i) ;        }        // 以下的输出结果不确定        System.out.println("代码执行之后 --> " + t.isAlive()) ;     // 判断是否启动    }};主线程运行完了,子线程还在运行线程的强制运行线程强制运行期间,其他线程无法运行,必须等待此线程完成后才能执行。class MyThread implements Runnable{        public void run(){            for(int i=0;i<50;i++){            System.out.println(Thread.currentThread().getName()                    + "运行,i = " + i) ;            }    }};public class ThreadJoinDemo{    public static void main(String args[]){        MyThread mt = new MyThread() ;            Thread t = new Thread(mt,"线程");                t.start() ;            for(int i=0;i<50;i++){            if(i>10){                try{                    t.join() ;    // 线程强制运行                }catch(InterruptedException e){}            }            System.out.println("Main线程运行 --> " + i) ;        }    }};运行结果:Main线程运行 --> 8线程运行,i = 8Main线程运行 --> 9线程运行,i = 9Main线程运行 --> 10线程运行,i = 10线程运行,i = 11线程运行,i = 12线程的休眠和中断class MyThread implements Runnable{        public void run(){            System.out.println("1、进入run()方法") ;        try{                Thread.sleep(10000) ;    // 线程休眠10秒                System.out.println("2、已经完成了休眠") ;        }catch(InterruptedException e){            System.out.println("3、休眠被终止") ;            return ; // 返回调用处        }        System.out.println("4、run()方法正常结束") ;    }};public class ThreadInterruptDemo{    public static void main(String args[]){        MyThread mt = new MyThread() ;            Thread t = new Thread(mt,"线程");                t.start() ;            try{                Thread.sleep(2000) ;    // 线程休眠2秒        }catch(InterruptedException e){            System.out.println("3、休眠被终止") ;        }        t.interrupt() ;    // 中断线程执行    }};一个线程运行时,另外一个线程可以通过interupt()方法中断运行状态,休眠一旦中断会进入catch中的代码。线程的优先级setPriority(Thread.MIN_PRIORITY);  //1         setPriority(Thread.NORM_PRIORITY);  //5        setPriority(Thread.MAX_PRIORITY);  //10 优先级越高,越有可能被先执行Thread.currentThread().getPriority();main函数的优先级为5线程的礼让让其他线程先运行class MyThread implements Runnable{        public void run(){            for(int i=0;i<5;i++){            try{                Thread.sleep(500) ;            }catch(Exception e){}            System.out.println(Thread.currentThread().getName()                    + "运行,i = " + i) ;    // 取得当前线程的名字            if(i==2){                System.out.print("线程礼让:") ;                Thread.currentThread().yield() ;    // 线程礼让            }        }    }};public class ThreadYieldDemo{    public static void main(String args[]){        MyThread my = new MyThread() ;            Thread t1 = new Thread(my,"线程A") ;        Thread t2 = new Thread(my,"线程B") ;        t1.start() ;        t2.start() ;    }};运行结果线程A运行,i = 0线程B运行,i = 0线程A运行,i = 1线程B运行,i = 1线程A运行,i = 2线程B运行,i = 2线程A运行,i = 3线程礼让:线程B运行,i = 3线程礼让:线程A运行,i = 4线程B运行,i = 4同步与死锁通过Runnable接口实现多线程,多个线程操作同一资源,引发资源同步问题class MyThread implements Runnable{    private int ticket = 5 ;    // 假设一共有5张票    public void run(){        for(int i=0;i<100;i++){            if(ticket>0){    // 还有票                try{                    Thread.sleep(300) ;    // 加入延迟                }catch(InterruptedException e){                    e.printStackTrace() ;                }                System.out.println("卖票:ticket = " + ticket-- );            }        }    }};public class SyncDemo01{    public static void main(String args[]){        MyThread mt = new MyThread() ;    // 定义线程对象        Thread t1 = new Thread(mt) ;    // 定义Thread对象        Thread t2 = new Thread(mt) ;    // 定义Thread对象        Thread t3 = new Thread(mt) ;    // 定义Thread对象        t1.start() ;        t2.start() ;        t3.start() ;    }};运行结果:卖票:ticket = 5卖票:ticket = 4卖票:ticket = 3卖票:ticket = 2卖票:ticket = 1卖票:ticket = 0卖票:ticket = -1产生-1的原因是线程中加入了延迟操作,一个线程还没有对票进行减操作之前,其他线程已经将票数减少了。解决方法1.同步代码块class MyThread implements Runnable{    private int ticket = 5 ;    // 假设一共有5张票    public void run(){        for(int i=0;i<100;i++){            synchronized(this){    // 要对当前对象进行同步                if(ticket>0){    // 还有票                    try{                        Thread.sleep(300) ;    // 加入延迟                    }catch(InterruptedException e){                        e.printStackTrace() ;                    }                    System.out.println("卖票:ticket = " + ticket-- );                }            }        }    }};public class SyncDemo02{    public static void main(String args[]){        MyThread mt = new MyThread() ;    // 定义线程对象        Thread t1 = new Thread(mt) ;    // 定义Thread对象        Thread t2 = new Thread(mt) ;    // 定义Thread对象        Thread t3 = new Thread(mt) ;    // 定义Thread对象        t1.start() ;        t2.start() ;        t3.start() ;    }};2.同步方法class MyThread implements Runnable{    private int ticket = 5 ;        public void run(){        for(int i=0;i<100;i++){            this.sale() ;    // 调用同步方法        }    }    public synchronized void sale(){    // 声明同步方法        if(ticket>0){    // 还有票            try{                Thread.sleep(300) ;    // 加入延迟            }catch(InterruptedException e){                e.printStackTrace() ;            }            System.out.println("卖票:ticket = " + ticket-- );        }    }};死锁当两个线程都在等待彼此先完成,造成了程序的停滞,死锁是在程序运行时出现的class Zhangsan{    // 定义张三类    public void say(){        System.out.println("张三对李四说:“你给我画,我就把书给你。”") ;    }    public void get(){        System.out.println("张三得到画了。") ;    }};class Lisi{    // 定义李四类    public void say(){        System.out.println("李四对张三说:“你给我书,我就把画给你”") ;    }    public void get(){        System.out.println("李四得到书了。") ;    }};public class ThreadDeadLock implements Runnable{    private static Zhangsan zs = new Zhangsan() ;        // 实例化static型对象    private static Lisi ls = new Lisi() ;        // 实例化static型对象    private boolean flag = false ;    // 声明标志位,判断那个先说话    public void run(){    // 覆写run()方法        if(flag){            synchronized(zs){    // 同步张三                zs.say() ;                try{                    Thread.sleep(500) ;                }catch(InterruptedException e){                    e.printStackTrace() ;                }                synchronized(ls){                    zs.get() ;                }            }        }else{            synchronized(ls){                ls.say() ;                try{                    Thread.sleep(500) ;                }catch(InterruptedException e){                    e.printStackTrace() ;                }                synchronized(zs){                    ls.get() ;                }            }        }    }    public static void main(String args[]){        ThreadDeadLock t1 = new ThreadDeadLock() ;        // 控制张三        ThreadDeadLock t2 = new ThreadDeadLock() ;        // 控制李四        t1.flag = true ;        t2.flag = false ;        Thread thA = new Thread(t1) ;        Thread thB = new Thread(t2) ;        thA.start() ;        thB.start() ;    }};生产者和消费者生产者不断生产,消费者不断从生产者取走数据,但由于线程运行的不确定性,会存在2个问题1.生产者线程向数据存储空间添加可信息的名称,还没有加入信息的内容,程序就切换到了消费者线程,消费者线程把信息的名称和上一个信息的内容联系到一起2.生产者放了若干次数据,消费者才开始取数据;或者消费者取完一个数据后,还没等到生产者放入新的数据,又重复取出已取过的数据class Info{    // 定义信息类    private String name = "zqt";     // 定义name属性    private String content = "黑马学员"  ;        // 定义content属性    public void setName(String name){        this.name = name ;    }    public void setContent(String content){        this.content = content ;    }    public String getName(){        return this.name ;    }    public String getContent(){        return this.content ;    }};class Producer implements Runnable{    // 通过Runnable实现多线程    private Info info = null ;        // 保存Info引用    public Producer(Info info){        this.info = info ;    }    public void run(){        boolean flag = false ;    // 定义标记位        for(int i=0;i<50;i++){            if(flag){                this.info.setName("zqt") ;    // 设置名称                try{                    Thread.sleep(90) ;                }catch(InterruptedException e){                    e.printStackTrace() ;                }                this.info.setContent("黑马学员") ;    // 设置内容                flag = false ;            }else{                this.info.setName("itheima") ;    // 设置名称                try{                    Thread.sleep(90) ;                }catch(InterruptedException e){                    e.printStackTrace() ;                }                this.info.setContent("www.itheima.com") ;    // 设置内容                flag = true ;            }        }    }};class Consumer implements Runnable{    private Info info = null ;    public Consumer(Info info){        this.info = info ;    }    public void run(){        for(int i=0;i<50;i++){            try{                Thread.sleep(90) ;            }catch(InterruptedException e){                e.printStackTrace() ;            }            System.out.println(this.info.getName() +                 " --> " + this.info.getContent()) ;        }    }};public class ThreadCaseDemo01{    public static void main(String args[]){        Info info = new Info();    // 实例化Info对象        Producer pro = new Producer(info) ;    // 生产者        Consumer con = new Consumer(info) ;    // 消费者        new Thread(pro).start() ;        new Thread(con).start() ;    }};运行结果itheima --> 黑马学员zqt --> www.itheima.comitheima --> 黑马学员zqt --> www.itheima.comitheima --> 黑马学员itheima --> 黑马学员解决方法:定义同步方法,并且不直接调用setter和getter方法class Info{    // 定义信息类    private String name = "zqt";     // 定义name属性    private String content = "黑马学员"  ;        // 定义content属性    public synchronized void set(String name,String content){        this.setName(name) ;    // 设置名称        try{            Thread.sleep(300) ;        }catch(InterruptedException e){            e.printStackTrace() ;        }        this.setContent(content) ;    // 设置内容    }    public synchronized void get(){        try{            Thread.sleep(300) ;        }catch(InterruptedException e){            e.printStackTrace() ;        }        System.out.println(this.getName() +             " --> " + this.getContent()) ;    }    public void setName(String name){        this.name = name ;    }    public void setContent(String content){        this.content = content ;    }    public String getName(){        return this.name ;    }    public String getContent(){        return this.content ;    }};class Producer implements Runnable{    // 通过Runnable实现多线程    private Info info = null ;        // 保存Info引用    public Producer(Info info){        this.info = info ;    }    public void run(){        boolean flag = false ;    // 定义标记位        for(int i=0;i<50;i++){            if(flag){                this.info.set("zqt","黑马学员") ;    // 设置名称                flag = false ;            }else{                this.info.set("itheima","www.itheima.com") ;    // 设置名称                flag = true ;            }        }    }};class Consumer implements Runnable{    private Info info = null ;    public Consumer(Info info){        this.info = info ;    }    public void run(){        for(int i=0;i<50;i++){            this.info.get() ;        }    }};public class ThreadCaseDemo02{    public static void main(String args[]){        Info info = new Info();    // 实例化Info对象        Producer pro = new Producer(info) ;    // 生产者        Consumer con = new Consumer(info) ;    // 消费者        new Thread(pro).start() ;        new Thread(con).start() ;    }};zqt --> 黑马学员itheima --> www.itheima.cnitheima --> www.itheima.cnitheima --> www.itheima.cnzqt --> 黑马学员zqt --> 黑马学员以上代码解决了信息错乱,但仍然存在重复读取的问题,解决这个问题需要用到Object类等待和唤醒生产者每生产一个就要等待消费者取走,消费者每取走一个就要等待生产者生产class Info{    // 定义信息类    private String name = "zqt";     // 定义name属性    private String content = "黑马学员"  ;        // 定义content属性    private boolean flag = false ;    // 设置标志位    public synchronized void set(String name,String content){        if(!flag){            try{                super.wait() ;            }catch(InterruptedException e){                e.printStackTrace() ;            }        }        this.setName(name) ;    // 设置名称        try{            Thread.sleep(300) ;        }catch(InterruptedException e){            e.printStackTrace() ;        }        this.setContent(content) ;    // 设置内容        flag  = false ;    // 改变标志位,表示可以取走        super.notify() ;    }    public synchronized void get(){        if(flag){            try{                super.wait() ;            }catch(InterruptedException e){                e.printStackTrace() ;            }        }        try{            Thread.sleep(300) ;        }catch(InterruptedException e){            e.printStackTrace() ;        }        System.out.println(this.getName() +             " --> " + this.getContent()) ;        flag  = true ;    // 改变标志位,表示可以生产        super.notify() ;    }    public void setName(String name){        this.name = name ;    }    public void setContent(String content){        this.content = content ;    }    public String getName(){        return this.name ;    }    public String getContent(){        return this.content ;    }};class Producer implements Runnable{    // 通过Runnable实现多线程    private Info info = null ;        // 保存Info引用    public Producer(Info info){        this.info = info ;    }    public void run(){        boolean flag = false ;    // 定义标记位        for(int i=0;i<50;i++){        <span style="white-space:pre">    </span>if(i%2==0)                this.info.set("zqt","黑马学员") ;    // 设置名称            }else{                this.info.set("itheima","www.itheima.com") ;    // 设置名称            }        }    }};class Consumer implements Runnable{    private Info info = null ;    public Consumer(Info info){        this.info = info ;    }    public void run(){        for(int i=0;i<50;i++){            this.info.get() ;        }    }};public class ThreadCaseDemo03{    public static void main(String args[]){        Info info = new Info();    // 实例化Info对象        Producer pro = new Producer(info) ;    // 生产者        Consumer con = new Consumer(info) ;    // 消费者        new Thread(pro).start() ;        new Thread(con).start() ;    }};运行结果:zqt --> 黑马学员itheima --> www.itheima.comzqt --> 黑马学员itheima --> www.itheima.comzqt --> 黑马学员线程的生命周期其他方法suspend(),resume(),stop() 为 @Deprecated声明 不推荐使用,容易造成死锁那么如何停止一个线程运行呢?设置标志位停止线程的运行。class MyThread implements Runnable{    private boolean flag = true ;    // 定义标志位    public void run(){        int i = 0 ;        while(this.flag){            System.out.println(Thread.currentThread().getName()                +"运行,i = " + (i++)) ;        }    }    public void stop(){        this.flag = false ;    // 修改标志位    }};public class StopDemo{    public static void main(String args[]){        MyThread my = new MyThread() ;        Thread t = new Thread(my,"线程") ;            t.start() ;            try{            Thread.sleep(30) ;        }catch(Exception e){                    }        my.stop() ;    // 修改标志位,停止运行    }};总结:线程被暂停的原因:wait(),sleep(),join()暂停解除的原因:notify(),sleep()时间到练习:1.设计4个线程对象,两个线程每次对j加一,两个线程每次对j减一class ThreadTest {    private int j;     public static void main(String args[]) {        ThreadTest tt = new ThreadTest();        Inc inc = tt.new Inc();        Dec dec = tt.new Dec();        for (int i = 0; i < 2; i++) {            Thread t = new Thread(inc);            t.start();            t = new Thread(dec);            t.start();        }    }     private synchronized void inc() {        j++;        System.out.println(Thread.currentThread().getName() + "-inc:" + j);    }     private synchronized void dec() {        j--;        System.out.println(Thread.currentThread().getName() + "-dec:" + j);    }     class Inc implements Runnable {        public void run() {            for (int i = 0; i < 100; i++) {                inc();            }        }    }     class Dec implements Runnable {        public void run() {            for (int i = 0; i < 100; i++) {                dec();            }        }    }}

 

java多线程