美文网首页
2.编写多线程

2.编写多线程

作者: xialedoucaicai | 来源:发表于2018-05-18 18:07 被阅读0次

1.实现多线程的两种方式

  1. 继承Thread类
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程正在运行");
    }
}
public class MyMain {
    public static void main(String[] args) {
        new MyThread().start();
        System.out.println("主线程"+Thread.currentThread().getName()+"运行结束");
    }
}
  1. 实现Runnable接口
public class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程正在运行");
    }
}
public class MyMain {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
        System.out.println("主线程"+Thread.currentThread().getName()+"运行结束");
    }
}

这两种方式基本没啥区别,因为Java不能多继承的限制,我们尽量会通过实现Runnable接口的方式实现多线程。其实看源码能发现,Thread类也实现了Runnable接口。

其实还可以通过使用JUC的Callable和ThreadPoolExecutor创建线程,JUC为我们提供了大量的封装好的多线程操作,我们会在后面详细介绍JUC的各个组件。

2.start()与run()有什么区别

start()是启动一个新的线程,该线程会执行run()方法,相当于有两个线程在运行,一个主线程,一个执行run()方法的线程
而直接调用run(),变成了主线程调用一个普通方法,不再是多线程了

3. Thread.sleep()哪个线程休眠了?

sleep()是静态方法,对于静态方法,一般都是对当前线程休眠,即Thread.currentThread()这个线程,也就是执行该行代码的那个线程。

public class MyThread implements Runnable{
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        try {
            //这里休眠的线程是MyThread
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i = 0;i < 100;i++){
            System.out.println(i+" "+Thread.currentThread().getName()+"线程正在运行");
        }
        System.out.println("子线程运行时长:"+(System.currentTimeMillis() - start));
    }
}
public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
        //即使我们用myThread调sleep(),休眠效果也并没有作用在myThread上,当然我们不建议用对象调静态方法
        thread.sleep(3000);
        //将执行这行代码的线程休眠 是那个线程呢?是Thread.currentThread()这个线程,即main线程
        Thread.sleep(3000);
        System.out.println("主线程"+Thread.currentThread().getName()+"运行时长"+(System.currentTimeMillis() - start));
    }

4. 如何正确中断线程?

首先看下interrupt相关的三个方法有什么区别:

  • myThread.interrupt()非静态方法,并不会立即中断线程,只是打一个中断标志,至于何时中断线程,不确定
  • Thread.interrupted()静态方法,判断当前线程是否中断,具有清除线程状态的功能,这里注意静态方法一般是作用于执行该行代码的线程
  • myThread.isInterrupted()非静态方法,判断myThread这个线程是否终止,不具有清除线程状态的功能,这里注意非静态方法一般是作用于调该方法的对象代表的线程
public class MyThread extends Thread{
    public void run() {
        for(int i = 0;i < 500000; i++){
            System.out.println(i);
        }
    }
}
//测试interrupt()方法
    @Test
    public void testInterrupt() {
        MyThread myThread = new MyThread();
        myThread.start();
        //中断myThread线程,不会立即中断线程,只是打个中断标志,至于何时会中断线程,不确定
        myThread.interrupt();
    }
    
    //测试Thread.interrupted()方法
    @Test
    public void testInterrupted(){
        MyThread myThread = new MyThread();
        myThread.start();
        //中断myThread线程,不会立即中断线程,只是打个中断标志
        myThread.interrupt();
        //该方法为静态方法,用于判断当前线程是否中断
        //这里的当前线程指的是执行这行代码的线程,由于上面语句是将myThread中断了,并未将执行该行代码的线程中断,所以为false
        System.out.println(Thread.interrupted());
    }
    
    //测试Thread.interrupted()方法
    @Test
    public void testInterrupted2(){
        //将当前线程中断
        Thread.currentThread().interrupt();
        //判断当前线程是否中断 true
        System.out.println(Thread.interrupted());
        //由于Thread.interrupted()方法具有清除状态的功能,所以第二次调用的时候,线程不再是中断状态了
        System.out.println(Thread.interrupted());
    }
    
    //测试isInterrupted()方法
    @Test
    public void test(){
        MyThread myThread = new MyThread();
        myThread.start();
        myThread.interrupt();
        //isInterrupted()方法不是静态的,用于判断myThread是否中断 true
        System.out.println(myThread.isInterrupted());
        //同时该方法不具有清除状态的功能
        System.out.println(myThread.isInterrupted());
    }

如何立即中断线程:
调用myThread.interrupt()方法,在MyThread中判断this.isInterrupted(),如果被终止,直接抛出异常,这样才能立即终止线程

public class MyMain {
    //测试interrupt()方法 需要MyThread配合,才能立即中断线程
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
        //只让myThread执行0.1秒钟
        Thread.sleep(100);
        //为线程打中断标志位
        thread.interrupt();
    }
}
public class MyThread implements Runnable{
    public void run() {
        try{
            for(int i = 0;i < 500000; i++){
                if(Thread.currentThread().isInterrupted()){//如果myThread终止了,直接抛出异常,这样才会立即终止线程
                    throw new InterruptedException();
                }
                System.out.println(i);
            }   
        }catch (Exception e){
            System.out.println("线程异常被捕获");
            e.printStackTrace();
        }
    }
}

注意

  1. interrupt()与sleep()相遇将会抛出异常,无论是在休眠状态下中断线程,还是在中断状态下休眠线程,都会有问题。
  2. myThread.suspend()暂停线程
    myThread.resume()恢复线程
    myThread.stop()停止线程
    这三个方法被标注为过期方法,不再推荐使用,将会导致锁无法释放,数据不同步等问题,详情可参见《Java多线程编程核心技术》1.7.5与1.8.1

5.守护线程

当进程中所有的用户线程都结束了,守护线程就会自动结束。守护线程一般用于提供服务的,就像一家餐厅,当没有任何客人了,餐厅就要关门了。典型的守护线程如GC。

public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        //守护线程 当进程中所有的用户线程都结束了,守护线程机会自动结束,典型的守护线程如GC
        //把这行注释掉,就能更明显地看到区别了
        myThread.setDaemon(true);
        myThread.start();
        
        Thread.sleep(5000);
        System.out.println("主线程正常结束了,守护线程也要自动退出了");
    }
public class MyThread extends Thread{
    @Override
    public void run() {
        int i = 0;
        while(true){
            System.out.println("守护线程一直在打印:"+ i++);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

6.线程优先级

  1. 线程的优先级具有继承性,即thread1线程优先级为5,由该线程启动的其他线程优先级也为5
  2. 优先级较高的线程总是更可能先执行完,但并不是说优先级高的肯定会先执行完,这个具有一定的随机性
public class Thread1 extends Thread{
    @Override
    public void run() {
        System.out.println("我是线程1,我的优先级是"+this.getPriority());
        Thread2 thread2 = new Thread2();
        thread2.start();
    }
}
public class Thread2 extends Thread{
    @Override
    public void run() {
        System.out.println("我是线程2,我的优先级是"+this.getPriority());
    }
}
public class Thread3 extends Thread {
    int result = 0;
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 10000; j++) {
                result = i++ * j+  i++ * j++ + i*j;
            }
        }
        System.out.println("33333333333--------线程3执行完了!");
    }
}
public class Thread4 extends Thread {
    int result = 0;
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 10000; j++) {
                result = i++ * j+  i++ * j++ + i*j;
            }
        }
        System.out.println("44444444444--------线程4执行完了!");
    }
}
public class MainTest {

    public static void main(String[] args) {
        //testPriorityExtends();
        testPriority();
    }
    
    /**
     * 线程的优先级具有继承性,即a线程优先级为5,由该线程启动的其他线程优先级也为5
     */
    public static void testPriorityExtends(){
        Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 1);
        System.out.println("我是主线程,我的优先级是"+Thread.currentThread().getPriority());
        Thread1 thread1 = new Thread1();
        thread1.start();
    }
    
    /**
     * 优先级较高的线程总是更可能先执行完
     * 但并不是说优先级高的肯定会先执行完,这个具有一定的随机性
     */
    public static void testPriority(){
        Thread3 thread3 = new Thread3();
        thread3.setPriority(Thread.MIN_PRIORITY);
        
        
        Thread4 thread4 = new Thread4();
        thread4.setPriority(Thread.MAX_PRIORITY);
        
        
        thread3.start();
        thread4.start();
    }
}

7.yield()方法

Thread.yield() 静态方法,让线程放弃当前CPU资源,即从运行状态进入就绪状态

public class MyThread extends Thread{
    @Override
    public void run() {
        long startTime = System.currentTimeMillis();
        for(int i = 0;i < 500000; i++){
            //让线程放弃当前CPU资源,即从运行状态进入就绪状态
            //可以注释掉该行,看看效果
            Thread.yield();
            i++;
        }
        long endTime = System.currentTimeMillis();
        System.out.println("用时:"+(endTime - startTime)+"毫秒");
    }
}

相关文章

  • 2.编写多线程

    1.实现多线程的两种方式 继承Thread类 实现Runnable接口 这两种方式基本没啥区别,因为Java不能多...

  • 多线程

    一、编写多线程分为两种: 1.继承Thread类 2.实现runnable接口 二、Runable相对于Threa...

  • Java多线程-简单例子(门票售卖)

    前言:多个售票点同时售卖门票,通过多线程同步锁实现同步售票。 1.创建JavaProject。 2.编写Ticke...

  • Runnable与Callable

    Callable: Runnable: 区别:相同点: 1.都是接口。2.都可用来编写多线程程序。3.都需要调用T...

  • [编程题] Java基础编程练习题(二)

    1.编写一个Java程序实现多线程,在线程中输出线程的名字,隔300毫秒输出一次,共输出20次。 2.编写程序,在...

  • pthread多线程(C语言) + Socket

    pthread多线程(C语言) + Socket pthread是使用使用C语言编写的多线程的API, 简称Pth...

  • python3 多线程编程实战: http多线程下载器的编写

    python3 多线程编程实战: http多线程下载器的编写说到多线程的应用,这种并发下载的情况显然比较适合。也是...

  • Python_提高

    GIL全局解释器锁 描述Python GIL的概念, 以及它对python多线程的影响?编写⼀个 多线程抓取⽹⻚的...

  • 写一个简易聊天程序

    需求:编写一个聊天程序 思路:有收有发,且同时执行,需要用到多线程发送端:1.建立updsocket服务2.打包D...

  • Linux多线程编程实例解析

    Linux系统下的多线程遵循POSIX线程接口,称为 pthread。编写Linux下的多线程程序,需要使用头文件...

网友评论

      本文标题:2.编写多线程

      本文链接:https://www.haomeiwen.com/subject/sdhidftx.html