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()+"运行结束");
}
}
- 实现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();
}
}
}
注意:
- interrupt()与sleep()相遇将会抛出异常,无论是在休眠状态下中断线程,还是在中断状态下休眠线程,都会有问题。
- 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.线程优先级
- 线程的优先级具有继承性,即thread1线程优先级为5,由该线程启动的其他线程优先级也为5
- 优先级较高的线程总是更可能先执行完,但并不是说优先级高的肯定会先执行完,这个具有一定的随机性
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)+"毫秒");
}
}
网友评论