synchronized有三种写法:
第一种:同步代码块
灵活
synchronized(线程共享对象){
同步代码块;
}
/*
线程同步机制的语法是:
synchronized(){
//线程同步代码块。
}
synchronized后面小括号中传的这个数据是相当关键的。
这个数据必须是多线程共享的数据,才能达到多线程排队。
()中写什么?
那要看你想让那些线程同步。
假设t1,t2,t3,t4,t5有五个线程,
你只希望t1,t2,t3排队,t4,t5不需要排队。怎么办?
一定要在()中写一个t1,t2,t3共享的对象。而这个对象
对于t4,t5来说不是共享的。
java语言中,任何一个对象都有一把锁,其实这把锁就是标记。(只是把它叫做锁)
100个对象,100把锁。
以下代码的执行原理?
*/
Object obj2=new Object();
synchronized(this){
//synchronized(actno){
//synchronized(obj){
//synchronized("abc"){//"abc"在字符串常量池当中
//synchronized(obj2){//因为obj2不是共享对象,这样编写就不安全了。
double before=this.getBalance();
double after=this.balance-money;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setBalance(after);
}
第二种:在实例方法上使用synchronized
表示共享对象一定是this
并且同步代码块是整个方法体
/*
在实例方法上可以使用synchronized吗?可以的
synchronized出现在实例方法上,一定锁的是this。
只能是this,不能是其他对象
所以这种方式不灵活。
还有一个缺点:synchronized出现在实例方法上,
表示整个方法体都需要同步,可能会无故扩大同步的
范围,导致程序的执行效率降低,这种方式不常用。
synchronized 使用在实例方法上有什么优点:节俭了
如果共享的对象就是this,并且需要同步的代码块是整个
方法体,建议使用这种方式。
*/
public synchronized void withdraw(double money){
double before=this.getBalance();
double after=this.balance-money;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setBalance(after);
}
第三种:在静态方法上使用synchronized
表示找类锁
类锁永远只有一把。
结算创建了100个对象,那类锁也只有一把
以后开发中怎么解决线程安全问题?
不能一上来就是使用synchronized
synchronized会让程序的执行效率降低,用户体验不好。
系统的吞吐量降低,用户体验差。在不得已的情况下,再
使用线程同步机制
第一种方案:尽量使用局部变量代替实例变量和静态变量。
第二种方案:如果必须是实例变量,那么可以考虑创建多个对象,这样对象就不共享了。
(一个线程一个对象)对象不共享就没有数据安全问题。
第三种方案:如果不能使用局部变量,对象也不能创建多个,这个时候就只能使用
synchronized了,线程同步机制。
synchronized面试题
1、doOther()方法的执行的时候需要等待doSome()方法的结束吗?
不需要,因为doOther()方法没有synchronized关键字。
synchronized锁的对象是this,这个对象,因为doOther()
方法没有synchronized关键字,所以不需要访问已经被锁
住的MyClass对象
不需要,因为doOther()方法没有synchronized关键字。
synchronized锁的对象是this,这个对象,因为doOther()
方法没有synchronized关键字,所以不需要访问已经被锁
住的MyClass对象
public class Exam01 {
public static void main(String[] args) {
MyClass mc=new MyClass();
MyThread t1=new MyThread(mc);
MyThread t2=new MyThread(mc);
t1.setName("t1");
t2.setName("t2");
t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
class MyThread extends Thread{
private MyClass mc;
public MyThread(MyClass mc){
this.mc=mc;
}
@Override
public void run() {
if(Thread.currentThread().getName().equals("t1")){
mc.doSome();
}
if(Thread.currentThread().getName().equals("t2")){
mc.doOther();
}
}
}
class MyClass{
public synchronized void doSome(){
System.out.println("doSome begin");
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("doSome over");
}
public void doOther(){
System.out.println("doOther begin");
System.out.println("doOther over");
}
}
public static void main(String[] args) {
MyClass mc=new MyClass();
MyThread t1=new MyThread(mc);
MyThread t2=new MyThread(mc);
t1.setName("t1");
t2.setName("t2");
t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
class MyThread extends Thread{
private MyClass mc;
public MyThread(MyClass mc){
this.mc=mc;
}
@Override
public void run() {
if(Thread.currentThread().getName().equals("t1")){
mc.doSome();
}
if(Thread.currentThread().getName().equals("t2")){
mc.doOther();
}
}
}
class MyClass{
public synchronized void doSome(){
System.out.println("doSome begin");
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("doSome over");
}
public void doOther(){
System.out.println("doOther begin");
System.out.println("doOther over");
}
}
2、对以上代码实现以下改变
doOther()方法的执行的时候需要等待doSome()方法的结束吗?
需要
public synchronized void doOther(){
System.out.println("doOther begin");
System.out.println("doOther over");
}
System.out.println("doOther begin");
System.out.println("doOther over");
}
3、对以上代码实现以下改变
doOther()方法的执行的时候需要等待doSome()方法的结束吗?
不需要,因为MyClass对象有两个。
MyClass mc1=new MyClass();
MyClass mc2=new MyClass();
MyThread t1=new MyThread(mc1);
MyThread t2=new MyThread(mc2);
MyClass mc2=new MyClass();
MyThread t1=new MyThread(mc1);
MyThread t2=new MyThread(mc2);
public synchronized void doOther(){
System.out.println("doOther begin");
System.out.println("doOther over");
}
System.out.println("doOther begin");
System.out.println("doOther over");
}
4、对以上代码实现以下改变
doOther()方法的执行的时候需要等待doSome()方法的结束吗?
需要,因为静态方法是类锁,类锁不管创建了几个对象,类锁只有一把
public synchronized static void doSome(){
System.out.println("doSome begin");
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("doSome over");
}
public synchronized static void doOther(){
System.out.println("doOther begin");
System.out.println("doOther over");
}
System.out.println("doSome begin");
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("doSome over");
}
public synchronized static void doOther(){
System.out.println("doOther begin");
System.out.println("doOther over");
}
死锁的概念
以下代码为死锁代码:
public class DeadLock {
public static void main(String[] args) {
Object o1=new Object();
Object o2=new Object();
MyThread1 t1=new MyThread1(o1,o2);
MyThread2 t2=new MyThread2(o1,o2);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
Object o1;
Object o2;
public MyThread1(Object o1,Object o2){
this.o1=o1;
this.o2=o2;
}
@Override
public void run() {
synchronized (o1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
}
}
}
}
class MyThread2 extends Thread{
Object o1;
Object o2;
public MyThread2(Object o1,Object o2){
this.o1=o1;
this.o2=o2;
}
@Override
public void run() {
synchronized(o2){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(o1){
}
}
}
}
public static void main(String[] args) {
Object o1=new Object();
Object o2=new Object();
MyThread1 t1=new MyThread1(o1,o2);
MyThread2 t2=new MyThread2(o1,o2);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
Object o1;
Object o2;
public MyThread1(Object o1,Object o2){
this.o1=o1;
this.o2=o2;
}
@Override
public void run() {
synchronized (o1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
}
}
}
}
class MyThread2 extends Thread{
Object o1;
Object o2;
public MyThread2(Object o1,Object o2){
this.o1=o1;
this.o2=o2;
}
@Override
public void run() {
synchronized(o2){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(o1){
}
}
}
}