多线程概述
多线程实现
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();
}
}
两种方式对比
- 继承Thread
- 好处:可以直接使用Thread类中的方法,代码简单
- 弊端:如果已经有了父类,就不能用这种方法
- 实现Runnable接口
- 好处:即使自己定义的线程类有了父类也可以,因为有了父类也可以实现接口,而且接口是可以多实现的
- 弊端:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂
匿名内部类写法
- 继承Thread类
public class ThreadTest {
public static void main(String[] args){
new Thread(){
@Override
public void run() {
while (true)
System.out.println("haha");
}
}.start();
}
}
- 实现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");
}
}