目录
理解线程的概念
线程的创建方式
Thread
实现Runnable接口
线程的5种状态
(创建、就绪、执行、阻塞、终止)
线程常用方法
线程同步synchronized
public class ThreadTest {
public static void main(String[] args) {
MyThread t1=new MyThread();
t1.start();
MyThread t2=new MyThread();
t2.start();
MyThread t3=new MyThread();
t3.start();
System.out.println("main");
}
static class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<=10;i++) {
System.out.println("该时间片段线程名称:"+getName()+" 打印出来的数据是:"+i);
}
}
}
}
执行结果:
@Override
public void run() {
if (target != null) {
target.run();
}
}
public class RunnableTest {
public static void main(String[] args) {
MyRunnable r1=new MyRunnable();
MyRunnable r2=new MyRunnable();
MyRunnable r3=new MyRunnable();
Thread thread=new Thread(r1);
Thread thread2=new Thread(r2);
Thread thread3=new Thread(r3);
thread.start();
thread2.start();
thread3.start();
Thread thread4=new Thread();
thread4.start();
System.out.println("main");
}
static class MyRunnable implements Runnable{
@Override
public void run() {
Thread thread=Thread.currentThread();
for(int i=0;i<=10;i++) {
System.out.println("该时间片段线程名称:"+thread.getName()+" 打印出来的数据是:"+i);
}
}
}
}
打印结果:
sleep(毫秒) | 使线程进入阻塞,例如我们实现一个显示时间,隔1秒执行功能,可以sleep(1000) |
getName()/setName | 在run方法中获取线程和设置线程名称 |
currentThread() | 获取当前线程,结合Runnable使用的时候会调用 |
interrupt()和 interrupted() |
|
join() |
|
yiled() | 当前线程让出CPU资源,主动让给其他线程,不会让线程进入阻塞状态,也就是说让本线程从执行中的状态 又回到就绪的状态,以后甚至马上也可能会继续抢占CPU时间片,继续执行 |
setPriority()和getPriority() | 优先级,默认优先级是5,不需要手动改,从1到10,优先级越高,获得的CPU越多 |
setDaemon(true) | 设置为后台线程,或者叫守护线程 |
isAlive() | 判断线程的状态 线程处于“新建”状态时,线程调用isAlive()方法返回false。在线程的run()方法结束之前,即没有进入死亡状态之前,线程调用isAlive()方法返回true |
public class YieldTest {
public static void main(String[] args) {
YieldThread t1=new YieldThread("线程1");
YieldThread t2=new YieldThread("线程2");
YieldThread t3=new YieldThread("线程3");
t1.start();
t2.start();
t3.start();
}
static class YieldThread extends Thread{
public YieldThread(String name) {
setName(name);
}
@Override
public void run() {
System.out.println(getName());
}
}
}
执行结果:
public class InterruptTest {
public static void main(String[] args) {
MyThread t1=new MyThread();
t1.start();
System.out.println("按回车结束线程");
new Scanner(System.in).nextLine();
t1.interrupt();
}
static class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<=10;i++) {
try {
//每隔1秒钟打印一次
System.out.println("该时间片段线程名称:"+getName()+" 打印出来的数据是:"+i);
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("main线程打断了子线程");
}
}
}
}
}
执行结果:当前秒数内抛异常之后,会继续执行后续线程中的内容
显然,打断之后还一直执行是不对的,进行代码优化,判断线程状态进行停止
public class InterruptTest {
public static void main(String[] args) {
MyThread t1=new MyThread();
t1.start();
System.out.println("按回车结束线程");
new Scanner(System.in).nextLine();
t1.interrupt();
}
static class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<=10;i++) {
try {
if(isInterrupted()) {
break;
}
//每隔1秒钟打印一次
System.out.println(getName()+" "+i+" "+isInterrupted());
sleep(1000);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("main线程打断了子线程"+isInterrupted());
interrupt();
System.out.println("main线程打断了子线程"+isInterrupted());
}
}
}
}
}
打印结果:
join()
首先做个测试,假如我要求1到10000000之间所有的质数,我们知道,java启动程序会开启main主线程,需要开启子线程的话,需要我们手动去添加,首先上代码
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
f1();
}
private static void f1() throws InterruptedException {
System.out.println("单线程测试质数个数:");
//单线程测试
long s=System.currentTimeMillis();
JoinThread thread=new JoinThread(1, 10000000);
thread.start();
int sum=thread.count;
s=System.currentTimeMillis()-s;
System.out.println("总共"+sum+"个质数,耗时:"+s);
}
//定义子线程
static class JoinThread extends Thread{
int start;
int end;
int count;
public JoinThread(int start,int end) {
this.start=start;
this.end=end;
if(start<=2) {
count=1;
start=3;
}
}
@Override
public void run() {
for(int i=start;i
打印结果:
明显是错误的,为什么会这样呢?答案很简单,在子线程还没执行完的时候,main主线程就开始调用了输出语句,获取结果了,所以肯定是错误的,这时候就要用到join方法,main主线程等待子线程执行完再执行,把子线程调用join,插入到main线程
代码块改f1()方法添加,改成如下:
private static void f1() throws InterruptedException {
System.out.println("单线程测试质数个数:");
//单线程测试
long s=System.currentTimeMillis();
JoinThread thread=new JoinThread(1, 10000000);
thread.start();
thread.join();
int sum=thread.count;
s=System.currentTimeMillis()-s;
System.out.println("总共"+sum+"个质数,耗时:"+s);
}
这时候打印结果:
结果正确了,但是发现耗时用了6秒多,效率很低,这时候,可以优化,把单线程改成多个子线程:
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
f5();
}
private static void f5() throws InterruptedException {
System.out.println("5个线程测试质数个数:");
//单线程测试
long s=System.currentTimeMillis();
JoinThread[]threads=new JoinThread[5];
for(int i=0;i
运行结果:
后台进程setDaemon(true)
public class daemonTest {
public static void main(String[] args) {
System.out.println("输入换行停止t1线程:");
DaemonThread t1=new DaemonThread();
t1.start();
Thread t2=new Thread(){
public void run() {
new Scanner(System.in).next();
t1.interrupt();
};
};
//一定要写在执行之前
// t2.setDaemon(true);
t2.start();
}
static class DaemonThread extends Thread{
@Override
public void run() {
for(int i=0;i<=5;i++) {
try {
System.out.println(i);
sleep(1000);
} catch (InterruptedException e) {
System.out.println("线程异常");
}
}
}
}
}
执行结果
控制台依然在等待用户输入
假如把t2.setDaemon(true);这句话放开,设置成后台进程,那么线程执行完就会结束,不会等待用户操作了,执行结果如图:
详细请参考下一篇 Java 线程同步