string数据类型使用在synchronized同步代码块中出现的情况。
public class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.print("AA");
}
}
public class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.print("AA");
}
}
public class Service {
public static void print(String stringParam) {
try {
synchronized (stringParam) {
while (true) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Service service = new Service();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service);
b.setName("B");
b.start();
}
打印的结果A线程一直打印,B线程执行不力,就是因为string的两个值都是一样的,两个线程持有相同的锁,string常量池带来的问题,因此synchronized代码块都不用string作为锁对象,而改用其他的,比如new Object()实例化一个Object对象。
同步synchronized方法无线等待与解决
同步方法容易造成死循环 代码如下举例:
public class Service {
synchronized public void methodA() {
System.out.println("methodA begin");
boolean isContinueRun = true;
while (isContinueRun) {
}
System.out.println("methodA end");
}
synchronized public void methodB() {
System.out.println("methodB begin");
System.out.println("methodB end");
}
}
public class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.methodA();
}
}
public class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
super();
this.service = service;
}
@Override
public void run() {
service.methodB();
}
}
public static void main(String[] args) {
Service service = new Service();
ThreadA athread = new ThreadA(service);
athread.start();
ThreadB bthread = new ThreadB(service);
bthread.start();
}
线程B永远等不到机会,A线程锁死了,这也是前面反复介绍过的同步带来的问题。这个时候可以用同步块来解决这样的问题。
更改service
public class Service {
Object object = new Object();
public void methodA() {
synchronized(object){
System.out.println("methodA begin");
boolean isContinueRun = true;
while (isContinueRun) {
}
System.out.println("methodA end");
}
}
Object object2= new Object();
public void methodB() {
synchronized(object2){
System.out.println("methodB begin");
System.out.println("methodB end");
}
}
}
多线程死锁介绍:
不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务否无法继续完成,造成死锁,线程的“假死”。
public class DealThread implements Runnable {
public String username;
public Object lock1 = new Object();
public Object lock2 = new Object();
public void setFlag(String username) {
this.username = username;
}
@Override
public void run() {
if (username.equals("a")) {
synchronized (lock1) {
try {
System.out.println("username = " + username);
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("按lock1->lock2代码顺序执行了");
}
}
}
if (username.equals("b")) {
synchronized (lock2) {
try {
System.out.println("username = " + username);
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("按lock2->lock1代码顺序执行了");
}
}
}
}
}
public class Run {
public static void main(String[] args) {
try {
DealThread t1 = new DealThread();
t1.setFlag("a");
Thread thread1 = new Thread(t1);
thread1.start();
Thread.sleep(100);
t1.setFlag("b");
Thread thread2 = new Thread(t1);
thread2.start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
只打印如下,因为A B都在等待对方释放锁继而继续执行下面的代码,造成了死锁问题。
内部类与同步实验:
public class OutClass {
static class Inner {
public void method1() {
synchronized ("其它的锁") {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + " i="
+ i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
public synchronized void method2() {
for (int i = 11; i <= 20; i++) {
System.out
.println(Thread.currentThread().getName() + " i=" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
}
public static void main(String[] args) {
final Inner inner = new Inner();
Thread t1 = new Thread(new Runnable() {
public void run() {
inner.method1();
}
}, "A");
Thread t2 = new Thread(new Runnable() {
public void run() {
inner.method2();
}
}, "B");
t1.start();
t2.start();
}
打印结果异步执行,两个线程持有不同的对象锁,一把是字符串锁,一把是当前内部类 类锁。
public class OutClass {
static class InnerClass1 {
public void method1(InnerClass2 class2) {
String threadName = Thread.currentThread().getName();
synchronized (class2) {
System.out.println(threadName + " 进入InnerClass1类中的method1方法");
for (int i = 0; i < 10; i++) {
System.out.println("i=" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
System.out.println(threadName + " 离开InnerClass1类中的method1方法");
}
}
public synchronized void method2() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 进入InnerClass1类中的method2方法");
for (int j = 0; j < 10; j++) {
System.out.println("j=" + j);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
System.out.println(threadName + " 离开InnerClass1类中的method2方法");
}
}
static class InnerClass2 {
public synchronized void method1() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 进入InnerClass2类中的method1方法");
for (int k = 0; k < 10; k++) {
System.out.println("k=" + k);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
System.out.println(threadName + " 离开InnerClass2类中的method1方法");
}
}
}
public class Run {
public static void main(String[] args) {
final InnerClass1 in1 = new InnerClass1();
final InnerClass2 in2 = new InnerClass2();
Thread t1 = new Thread(new Runnable() {
public void run() {
in1.method1(in2);
}
}, "T1");
Thread t2 = new Thread(new Runnable() {
public void run() {
in1.method2();
}
}, "T2");
// //
// //
Thread t3 = new Thread(new Runnable() {
public void run() {
in2.method1();
}
}, "T3");
t1.start();
t2.start();
t3.start();
}
}
同步代码块对class2上锁后 其他线程只能同步访问class2中的静态同步方法。
T1和T2异步执行,T1和T3同步执行。
锁对象的改变实验:
public class MyService {
private String lock = "123";
public void testMethod() {
try {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " begin "
+ System.currentTimeMillis());
lock = "456";//改变锁值
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " end "
+ System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadA extends Thread {
private MyService service;
public ThreadA(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.testMethod();
}
}
public class ThreadB extends Thread {
private MyService service;
public ThreadB(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.testMethod();
}
}
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.setName("A");
ThreadB b = new ThreadB(service);
b.setName("B");
a.start();
Thread.sleep(50);// 存在50毫秒
b.start();
}
因为A线程获取123这把锁,B线程还没执行,这时A已经改了锁的值,所以B进来也能获取锁 锁是456了已经。
去掉 存在50毫秒这行,打印结果有不一样。
因为A B线程同时抢锁,同时持有的锁是123,所以同步打印。