JAVA多线程

扫码查看

多线程概述

多线程实现

1.继承Thread

class MyThread extends Thread{
    private String greeting;
    MyThread(String s){
        greeting=s;
    }

    @Override
    public void run() {
        while (true)
        System.out.println(greeting);
    }
}
public class ThreadTest {
    public static void main(String[] args){
        MyThread ms1=new MyThread("haha");
        MyThread ms2=new MyThread("ahah");
        ms1.start();
        ms2.start();
    }
}

2.实现Runnable接口

class MyThread implements Runnable{
    private String greeting;
    MyThread(String s){
        greeting=s;
    }

    @Override
    public void run() {
        while(true)
        System.out.println(greeting);
    }
}
public class ThreadTest {
    public static void main(String[] args){
        MyThread ms1=new MyThread("haha");
        MyThread ms2=new MyThread("ahah");
        new Thread(ms1).start();
        new Thread(ms2).start();
    }
}

两种方式对比

  1. 继承Thread
    • 好处:可以直接使用Thread类中的方法,代码简单
    • 弊端:如果已经有了父类,就不能用这种方法
  2. 实现Runnable接口
    • 好处:即使自己定义的线程类有了父类也可以,因为有了父类也可以实现接口,而且接口是可以多实现的
    • 弊端:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂

匿名内部类写法

  1. 继承Thread类
public class ThreadTest {
    public static void main(String[] args){
        new Thread(){
            @Override
            public void run() {
                while (true)
                    System.out.println("haha");
            }
        }.start();
    }
}
  1. 实现Runnable接口
public class ThreadTest {
    public static void main(String[] args){
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true)
                    System.out.println("haha");
            }
        }).start();
    }
}

Thread方法

设置和获取线程名

//构造Thread时设置线程名
Thread(Runnable target, String name)
//分配一个新的 Thread对象。
Thread(String name)
//分配一个新的 Thread对象。

void setName(String name)
//将此线程的名称更改为等于参数 name 。

String getName()
//返回此线程的名称。  

获取当前线程的对象

static Thread currentThread()
//返回对当前正在执行的线程对象的引用。 

休眠,等待与唤醒线程

static void sleep(long millis)
//使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
void wait()
//导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
void notify()
//唤醒正在等待对象监视器的单个线程。
void notifyAll()
//唤醒正在等待对象监视器的所有线程。 

标记守护线程

void setDaemon(boolean on)
//将此线程标记为 daemon线程或用户线程。 
class MyThread extends Thread{
    private long last;
    MyThread(long last){//休眠时间
        this.last=last;
    }

    @Override
    public void run() {//休眠last秒然后打印该线程名
        try {
            sleep(last);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(this.getName());
    }
}
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        MyThread ms1=new MyThread(1000);//守护线程持续时间短
        ms1.setName("Daemon thread");
        MyThread ms2=new MyThread(4000);
        ms2.setName("Normal thread");
        ms1.setDaemon(true);
        ms1.start();
        ms2.start();
    }
}
//输出结果
//Daemon thread
//Normal thread
//如果将main中的代码改为以下
MyThread ms1=new MyThread(4000);//守护线程持续时间长
ms1.setName("Daemon thread");
MyThread ms2=new MyThread(1000);
ms2.setName("Normal thread");
ms1.setDaemon(true);
ms1.start();
ms2.start();
//输出结果
//Normal thread
//由于普通线程早于守护线程停止,守护线程也被迫停止(没来得及运行)

加入线程

void join()
//等待这个线程死亡。
void join(long millis)
//等待这个线程死亡最多 millis毫秒。 
class MyThread extends Thread{
    private long last;
    MyThread(long last){//休眠时间
        this.last=last;
    }

    @Override
    public void run() {//休眠last秒然后打印该线程名
        try {
            sleep(last);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(this.getName());
    }
}
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        MyThread ms1=new MyThread(1000);//守护线程持续时间短
        ms1.setName("first");
        MyThread ms2=new MyThread(4000);
        ms2.setName("second");
        ms2.start();
        ms2.join();//加入线程
        ms1.start();
    }
}
//线程1的睡眠时间短本应线程1先输出,但由于线程1执行前调用了线程1的join(),
//该函数会等待线程1停止才继续下面的代码
//所以输出
//second
//first

代码同步

同步代码块

  • 同步代码块即使用synchronized关键字加上一个锁对象来定义一段代码

  • 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的

    public class ThreadTest {
        public static void main(String[] args){
            Object o=new Object();
            new Thread(){
                @Override
                public void run() {
                    while (true) {
                        synchronized (o) {//锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
                            for (int i = 0; i < 10; i++) {
                                System.out.print(i);
                            }
                            System.out.println();
                        }
                    }
                }
            }.start();
            new Thread(){
                @Override
                public void run() {
                    while (true) {
                        synchronized (o) {
                            for (int i = 0; i < 10; i++) {
                                System.out.print(i);
                            }
                            System.out.println();
                        }
                    }
                }
            }.start();
        }
    }
    //如果不加synchronized那么打印出来的的不一定每一行都是0123456789

同步方法

  • 静态方法同步锁对象是当前类的字节码对象
  • 非静态同步方法锁对象是this
public static synchronized void printNum() {
    //使用synchronized关键字修饰的方法中所有的代码都是同步的
    for(int i=0;i<10;i++)
        System.out.println();
}

Timer(计时器)

  • 对任务进行定时规划运行
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Timer t = new Timer();
        t.schedule(new MyTimerTask(), new Date(),3000);//三秒打印一次O(∩_∩)O
        while(true) {
            System.out.println(new Date());//每秒打印一次时间
            Thread.sleep(1000);
        }
    }
}
class MyTimerTask extends TimerTask {
    @Override
    public void run() {
        System.out.println("O(∩_∩)O");
    }
}
02-10 04:33
查看更多