说明:参考《Java多线程核心技术》
4、dirtyRead
发生脏读情况是在读取变量时,此值已经被其他的线程给修改了。
public class DirtyRead extends Thread{
private PublicVaria publicVaria;
public DirtyRead(PublicVaria publicVaria) {
super();
this.publicVaria = publicVaria;
}
@Override
public void run(){
super.run();
publicVaria.setValue("B", "BB");
}
}
public class PublicVaria {
private String userName = "A";
private String passWord = "AA";
synchronized public void setValue (String userName, String passWord) {
try {
this.userName = userName;
Thread.sleep(5000);
this.passWord = passWord;
System.out.println(Thread.currentThread().getName() + "userName --"
+ userName + "--" + "password" + "--" + passWord);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void getValue () {
System.out.println(Thread.currentThread().getName() + userName +"--" + passWord);
}
}
public class DirtyReadTest {
public static void main(String[] args) {
try {
PublicVaria publicVaria = new PublicVaria();
DirtyRead threadA = new DirtyRead(publicVaria);
threadA.start();
// change the value can influence the result
Thread.sleep(2000);
publicVaria.getValue();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
mainB--AA
Thread-0userName --B--password--BB
*/
出现脏读的原因是getValue()方法不是同步的,所以在threadA线程sleep的时候,出现了脏读。
5、可重入锁
关键字synchronized具有锁重入的功能,即在使用synchronized时,当一个线程得到一个对象以后,再次请求此对象锁时,可以再次得到该对象的锁。说明了在一个synchronized方法/块的内部使用奔雷的其他synchronized方法/块时,是可以永远得到锁的。
public class Reentrant {
synchronized public void reentrant1Service1() {
System.out.println("reentrant1Service1");
reentrant1Service2();
}
synchronized public void reentrant1Service2() {
System.out.println("reentrant1Service2");
reentrant1Service3();
}
synchronized public void reentrant1Service3(){
System.out.println("reentrant1Service3");
}
}
public class ReentrantThread extends Thread {
@Override
public void run(){
Reentrant reentrant = new Reentrant();
reentrant.reentrant1Service1();
}
}
public class ReentrantThreadTest {
public static void main(String[] args) {
ReentrantThread thread = new ReentrantThread();
thread.start();
}
}
/**
reentrant1Service1
reentrant1Service2
reentrant1Service3
*/
说明:“可重入锁”: 自己可以再次获得自己的内部锁。假设synchronized不是可重入锁的话,线程就会发生死锁。因为有条线程获得了当前对象的锁,且此时的锁还没有释放,当其再次想要获得这个对象的锁时,还是可以获取到的,如果获取不到,就会发生死锁线程。
6、异常时,锁的自动释放
public class ThreadA extends Thread{
private ExceptionThread exceptionService;
public ThreadA(ExceptionThread exceptionService){
super();
this.exceptionService = exceptionService;
}
@Override
public void run(){
exceptionService.exceptionThread();
}
}
public class ThreadB extends Thread{
private ExceptionThread exceptionService;
public ThreadB (ExceptionThread exceptionService){
super();
this.exceptionService = exceptionService;
}
@Override
public void run(){
exceptionService.exceptionThread();
}
}
public class ExceptionThread {
synchronized public void exceptionThread (){
if (Thread.currentThread().getName().equals("a")) {
System.out.println("ThreadName = " + Thread.currentThread().getName()
+ "start time = " + System.currentTimeMillis());
int i = 1;
while (i == 1){
if (("" + Math.random()).substring(0, 8).equals("0.123456")){
System.out.println("ThreadName = " + Thread.currentThread().getName() +
" exception Time = " + System.currentTimeMillis());
Integer.parseInt("a");
}
}
}else {
System.out.println("ThreadB run time = " + System.currentTimeMillis());
}
}
}
public class ExceptionThreadTest {
public static void main(String[] args) {
try {
ExceptionThread thread = new ExceptionThread();
ThreadA a = new ThreadA(thread);
a.setName("a");
a.start();
Thread.sleep(500);
ThreadB b = new ThreadB(thread);
b.setName("b");
b.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
ThreadName = astart time = 1546669373655
ThreadName = a exception Time = 1546669373889
Exception in thread "a" java.lang.NumberFormatException: For input string: "a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at com.paojiaojiang.exception.ExceptionThread.exceptionThread(ExceptionThread.java:19)
at com.paojiaojiang.exception.ThreadA.run(ThreadA.java:18)
ThreadB run time = 1546669374170
*/
在线程a出现异常时,主动释放当前持有的锁,线程b进入打印方法。