java线程中断机制
一、java线程的工作方式
java线程之间的工作方式是协作式的,需要自己手动去结束线程,获取中断标志位,进而进行处理,或者判断当前中断标志位是否是true,false就继续执行自己的业务代码,不是就直接跳出结束线程。
二、线程中断的方式
1、在主线程中调用threadObject.interrupt()方法。
2、在子线程中调用isinterrupt()来判断当前线程是否被中断了。
三、注意事项
如果方法抛出了interruptException则会将中断标志物位重制位flase。需要我们在catch中重新将标志为置为true;
四、Java线程的各种状态以及切换的方式
五、深入理解run方法和start方法
package cn.enjoy.controller.thread;
/**
* @author:wangle
* @description:启动线程
* @version:V1.0
* @date:2020-01-17 11:31
**/
public class StartThread {
public static class ThreadRun extends Thread{
@Override
public void run(){
System.out.println("I'm am "+Thread.currentThread().getName());
}
}
public static void main(String arg[]){
ThreadRun threadRun = new ThreadRun();
threadRun.setName("ThreadRun");
threadRun.run();
}
}
输出结果:
阐述:可以看到,输出的是main,所以当前执行代码块的是主线程。这是java一个面向对象的基本概念,谁调用当前代码块就是哪个线程在执行,可以明显看到是主线程调用了run方法,所以run方法被的当作了一个普通的方法。
当使用start启动线程的时候,jvm才会给当前线程分配线程资源,真正的启动一个线程。
六、线程优先级
优先级为1~10,依次递减、缺省为5
使用setPriority方法进行优先级的设定,但是不同虚拟机会进行不同的处理,甚至会忽略掉设置的优先级值。所以不能在程序中太依靠当前值来控制线程优先级。
七、守护线程
threadRun.setDaemon();将线程设置为守护线程
特点:和主线程生命周期相同
finally的代码块不一定会执行,所以在守护线程中不能在finally中进行释放某些特定资源。以免资源泄漏
八、线程安全
synchronized对临界资源进行同步
1、作用于实例方法(对象锁)
a、多个线程访问同一个对象的同一个方法
public class StartThread implements Runnable {
//共享资源
static int i =0;
/**
* synchronized 修饰实例方法
*/
public synchronized void increase(){
i++;
}
@Override
public void run(){
for (int j =0 ; j<10000;j++){
increase();
}
}
public static void main(String[] args) throws InterruptedException {
StartThread test = new StartThread();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
分析:当两个线程同时对一个对象的一个方法进行操作,只有一个线程能够抢到锁。因为一个对象只有一把锁,一个线程获取了该对象的锁之后,其他线程无法获取该对象的锁,就不能访问该对象的其他synchronized实例方法,但是可以访问非synchronized修饰的方法
b、一个线程获取对象锁之后其他线程来访问改对象的其他synchronized方法
public class StartThread{
public synchronized void method1() {
System.out.println("Method 1 start");
try {
System.out.println("Method 1 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}
public synchronized void method2() {
System.out.println("Method 2 start");
try {
System.out.println("Method 2 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}
public static void main(String[] args) {
final StartThread test = new StartThread();
new Thread(new Runnable() {
@Override
public void run() {
test.method1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.method2();
}
}).start();
}
}
分析:一个对象只有一把锁,当线程1获取锁之后,其他线程需要等待1释放锁之后才能获取锁再去执行其他被同步的方法。
c、线程1获取锁之后,其他线程来访问该对象的非synchronized方法。
分析:在次不再张贴代码,只需将b中方法2去掉synchronized关键字即可。其他线程可以正常访问非synchronized的方法不需要等待1释放锁
d、当多个线程作用于不同的对象的synchronized方法
结果同c、因为锁的粒度是在对象的粒度上,非同一个对象使用的不是同一把锁。
2、synchronized作用于静态方法(类锁)
public class StartThread implements Runnable {
//共享资源
static int i =0;
/**
* synchronized 修饰实例方法
*/
public static synchronized void increase(){
i++;
}
@Override
public void run(){
for (int j =0 ; j<10000;j++){
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new StartThread());
Thread t2 = new Thread(new StartThread());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
分析:虽然是不同的线程访问不同的对象的synchronized方法,但是由于被static方法修饰的方法是属于类本身的,所以也是被同步了。这就是类锁
3、synchronized作用于同步代码
public class synchronizedTest implements Runnable {
static synchronizedTest instance=new synchronizedTest();
static int i=0;
@Override
public void run() {
//省略其他耗时操作....
//使用同步代码块对变量i进行同步操作,锁对象为instance
synchronized(instance){
for(int j=0;j<10000;j++){
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(instance);
Thread t2=new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
必须获取到instance对象的锁才能执行代码区域的代码,所以给过也是被同步的。