.net 做手机网站吗,客村网站建设,西安网站公司比较大的,手机网站建设要多少钱Synchronized
synchronized包含monitor enter, monitor exit 2个JVM指令(遵循happens-before原则), 执行monitor exit之前必须存在monitor enter指令. 由于每个对象与一个monitor产生关联, 线程执行monitor enter时, 就会获取monitor的lock, monitor中存在计数器, 用于记录当前…Synchronized
synchronized包含monitor enter, monitor exit 2个JVM指令(遵循happens-before原则), 执行monitor exit之前必须存在monitor enter指令. 由于每个对象与一个monitor产生关联, 线程执行monitor enter时, 就会获取monitor的lock, monitor中存在计数器, 用于记录当前lock被获取的情况, 当线程已经获取了lock, 再次进行线程重入, lock往上自增. 与之相反, 当线程执行到monitor exit时, 对应的monitor计数器就会自减
this monitor: synchronized修饰的对象是this
public synchronized void test(){//...
}
//A实现Runnable接口
A a new A();
new Thread(a).start();
new Thread(a).start();class monitor: synchronized修饰的对象是class
public synchronized static void test() {//...
}
或者
public void test() {synchronized(A.class) {//...}
}
//A实现Runnable接口
A a1 new A();
A a2 new A();
//此时a1 与a2 共用一个class monitor
new Thread(a1).start();
new Thread(a2).start();Thread API
sleep, yield, wait, notify/notifyAll, interrupt, interrupted, join
sleep Thread.sleep(), 线程休眠, 但休眠不会释放锁资源, 线程从running block的状态切换, 可以使用thread.interrupt中断睡眠yield Thread.yield(), 当前线程放弃CPU资源(CPU资源不紧张, 将忽略), 线程从running runnable的状态切换, 因此不能使用interrupt中断处于runnable状态的线程wait 线程放弃锁资源, 并进入与锁关联的waitSet集合, 状态变化: Running Blocked, 可以设定 object.wait()等价于object.wait(0), 表示阻塞时间是永远 注: wait必须在同步代码内. waitSet依赖于锁资源, 没有在同步代码内, 抛出IllegalMonitorStateException wait与sleep相似点:
1. 都能使线程阻塞
2. 都是可中断
3. wait属于Object, sleep属于Thread
4. wait需要在同步代码块中, sleep不需要
5. wait状态下, 将会是否锁资源, sleep不会释放锁资源
6. sleep执行一段自动退出阻塞状态, wait(long)一样.notify/notifyAll notify随机唤醒waitSet集合中某一线程, notifyAll唤醒waitSet集合中所有的线程, 被唤醒的线程重新争抢锁资源, 争抢到之后, 接着刚才wait的地方往后执行 注: notify必须在同步代码内. waitSet依赖于锁资源, 没有在同步代码内, 抛出IllegalMonitorStateExceptioninterrupt 打断当前线程阻塞状态, 可使用interrupt进行中断的方法如下:
object.wait(), object(long), Thread.sleep(long), thread.join(), Selector.wakeup()public void interrupt() {if (this ! Thread.currentThread())checkAccess();synchronized (blockerLock) {Interruptible b blocker;if (b ! null) {//设置中断标识, interrupt0属于native方法interrupt0(); b.interrupt(this);return;}}interrupt0();}当线程使用休眠方法进入阻塞状态后, 使用thread.interrupt设置中断标志, 随后线程被中断, 抛出InterruptedException, 线程终止运行 isInterrupt: 用于判断线程是否被中断, 从下面源码看出, 判断线程是否被中断, 不会清除中断标志 public boolean isInterrupted() {//native方法, clearInterrupted设置为falsereturn isInterrupted(false);}思考: wait, sleep, yield被中断后会不会清除中断标志
/*** 测试* author regotto*/
public class InterruptTest {private static final Object lock new Object();public static void main(String[] args) throws InterruptedException {Thread thread new Thread(() - {synchronized (lock) {try {System.out.println(1.isInterrupted: Thread.currentThread().isInterrupted());lock.wait();} catch (InterruptedException e) {System.out.println(2.isInterrupted: Thread.currentThread().isInterrupted());}}});thread.start();TimeUnit.SECONDS.sleep(1);thread.interrupt();TimeUnit.SECONDS.sleep(1);System.out.println(3.isInterrupted: Thread.currentThread().isInterrupted());}
}上述结果都为false, 由于isInterrupt不会清除中断标志, 因此得出结论, 中断标志是被wait清除的, 同理sleep, yield也是一样的.
interrupted: 该方法直接看源码
public static boolean interrupted() {return currentThread().isInterrupted(true);}从源码可以看出, 该方法就是调用isInterrupt方法, 但是, 注意传的参数是true, 意味着, 调用该方法后, 将会清除中断标志,
join A join B, B blocked 直到 A 变为terminal状态 join源码如下: public final synchronized void join(long millis)throws InterruptedException {long base System.currentTimeMillis();long now 0;if (millis 0) {throw new IllegalArgumentException(timeout value is negative);}if (millis 0) {while (isAlive()) {wait(0);}} else {while (isAlive()) {long delay millis - now;if (delay 0) {break;}wait(delay);now System.currentTimeMillis() - base;}}}根据源码得出如下结论: join内部机制就是wait, 一定记住, 调用wait时, 谁调用, 谁进入blocked, 不要搞混了
/*** 测试join,join内部使用wait,使调用join的线程进行wait,当任务线程执行完,JVM底层自动调用notify* author regotto*/
public class JoinTest {public static void main(String[] args) {Thread t1 new Thread(() - {for (int i 0; i 100; i) {System.out.println(Thread.currentThread().getName() : i);}}, t1);t1.start();try {//调用join线程是main线程,main线程进入join后处于wait状态,直到t1线程执行完,才notify//notify的过程由JVM底层自动调用//此时的join是相对于main,main线程是最终的调用者t1.join();} catch (InterruptedException e) {e.printStackTrace();}for (int i 0; i 100; i) {System.out.println(Thread.currentThread().getName() : i);}}
}测试join状态下的interrupt
/*** 测试join状态下的interrupt* author regotto*/
public class JoinSateExecuteInterrupt {public static void main(String[] args) {Thread main Thread.currentThread();Thread thread new Thread(() - {while (true) {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() interrupt);e.printStackTrace();break;}}});thread.start();//此处提前设置中断状态
// main.interrupt();thread.interrupt();try {thread.join();} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() interrupt);e.printStackTrace();}
// thread.interrupt(); //此处调用interrupt不能使join方法进入interrupt,因为一直执行thread的run操作,main线程的此行代码永远不会执行}
}根据Thread API实现自定义锁
需求分析: 实现synchronized的功能, 保证当线程处于阻塞状态可被中断(此处的阻塞代表线程在等待获取对象monitor), 线程在阻塞状态下可以计时, 避免线程资源浪费. 详细设计: 使用wait, notify, 标志变量设计lock, 模拟synchronized同步过程, A线程进入同步代码块, 将标志变量变为true, 此时wait有效, B进入线程进入阻塞状态, 当A线程执行完毕, 调用notifyAll, 唤醒被阻塞的线程, 在此过程中, 进入阻塞状态下的线程可被中断.
抽象接口定义:
package com.concurrent.definelock;import java.util.List;
import java.util.concurrent.TimeoutException;public interface Lock {void lock() throws InterruptedException;void lock(long mills) throws InterruptedException, TimeoutException;void unlock();/*** 用于获取处于阻塞状态的所有线程* return listthread*/ListThread getBlockedThreads();
}实现类:
package com.concurrent.definelock;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;public class BooleanLock implements Lock {/*** currentThread: 当前拥有锁的线程* locked: 锁是被被获得,默认false未获得,当调用lock能准确加锁* blockedList: 存储哪些线程进入阻塞状态*/private Thread currentThread;private boolean locked false;private final ListThread blockedList new ArrayList();/*** 第一个线程进入的时候, 标记为加锁的线程, 剩下的线程进入之后全都wait* 直到该线程unlock,剩下的线程才重新唤醒* throws InterruptedException*/Overridepublic void lock() throws InterruptedException {synchronized (this) {while (locked) {if (!blockedList.contains(currentThread)){blockedList.add(currentThread);}System.out.println(Thread.currentThread().getName() : 进入wait状态);//所有线程被唤醒, 只有拿到锁的那个线程才能接着下去执行, 剩余锁都只能处于阻塞状态//wait可中断方法, 当捕捉到Interrupt信号的时候, 抛出异常, 线程中断this.wait();System.out.println(Thread.currentThread().getName() : 被唤醒);}blockedList.remove(currentThread);System.out.println(Thread.currentThread().getName() : 删除在blockList中值, 设置locked为true);this.locked true;this.currentThread Thread.currentThread();}System.out.println(Thread.currentThread().getName() : 结束lock方法, 已出synchronize模块);}/*** 传入mills 0 立刻加锁也可尝试抛异常, 否则经过mills再加锁* param mills* throws InterruptedException* throws TimeoutException*/Overridepublic void lock(long mills) throws InterruptedException, TimeoutException {synchronized (this) {if (0 mills) {this.lock();} else {long remainingMills mills;long endMills System.currentTimeMillis() remainingMills;while (locked) {if (0 remainingMills){throw new TimeoutException();}if (!blockedList.contains(Thread.currentThread())) {blockedList.add(Thread.currentThread());}this.wait(remainingMills);remainingMills endMills - System.currentTimeMillis();}blockedList.remove(Thread.currentThread());this.locked true;this.currentThread Thread.currentThread();}}}Overridepublic void unlock() {System.out.println(Thread.currentThread().getName() : 进入unlock);synchronized (this) {//不加此步操作,任何线程都将可以执行notifyif (currentThread Thread.currentThread()) {//修改locked, 表示未加锁, 唤醒剩余线程System.out.println(Thread.currentThread().getName() : 设置lockedfalse);this.locked false;this.notifyAll();}}}Overridepublic ListThread getBlockedThreads() {return blockedList;}
}测试类:
package com.concurrent.definelock;import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;/*** 测试自定义BooleanLock* author regotto*/
public class BooleanLockTest {private final Lock lock new BooleanLock();public void syncMethod() {try {lock.lock();TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public static void main(String[] args) {BooleanLockTest blt new BooleanLockTest();//定义10个线程, 进行start测试IntStream.range(0, 10).mapToObj(i - new Thread(blt::syncMethod)).forEach(Thread::start);}
}
获取线程运行时异常
线程执行过程中, 可以为特定线程/全局线程设置运行时异常捕获, 通常使用Thread.setDefaultUncaughtExceptionHandler进行设置.
package com.concurrent.dealthreadexception;import java.util.concurrent.TimeUnit;public class CaptureThreadException {public static void main(String[] args) {//设置线程回调接口, 使得run方法出现异常, 回调Hook能捕获(该操作类似于监听者模式)//如果当前线程组没有设置回调接口, 那么就去父group中查找, 直到找到, 一直找不到//就执行System.errThread.setDefaultUncaughtExceptionHandler((thread, throwable) - {System.out.println(回调Hook捕获 thread.getName() 的run抛出的异常: throwable.getMessage());});final Thread thread new Thread(() - {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}//run方法不能抛出异常, 就算抛出也无法捕获, 只能使用特定的Hook获取异常System.out.println(1 / 0);}, Test0);thread.start();}
}Thread.setDefaultUncaughtExceptionHandler源码如下: public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {SecurityManager sm System.getSecurityManager();if (sm ! null) {sm.checkPermission(new RuntimePermission(setDefaultUncaughtExceptionHandler));}//设置默认的异常捕获处理器, 0defaultUncaughtExceptionHandler eh;}