目录
介绍
Synchronized是java内置的一个关键字,是一种同步锁,可以用有几种用法:
- 修饰一个代码块,被修饰的代码块称为同步代码块;
- 修饰一个实例方法,被修饰方法称为同步方法,作用范围为整个方法本身,作用对象为调用这个方法的实例对象;
- 修饰一个静态方法,其作用范围是整个静态方法,作用的对象为这个类(个人理解:因为静态方法是通过类名.的方式调用的,所以Synchronized锁的是整个类而不是对象);
- 修饰一个类,其作用范围是synchronized后面括号的部分,作用的对象是这个类的所有对象。
修饰一个代码块
synchronized (this){//this,锁
//同步代码块;
}
例子:创建一个对象时,使用synchronized时
package Synchronized;
public class Demo01 {
public static void main(String[] args) {
Syc syc = new Syc();
Thread thread1 = new Thread(syc,"t1");
Thread thread2 = new Thread(syc,"t2");
thread1.start();
thread2.start();
}
}
class Syc implements Runnable{
private static int count;
public Syc() {
count = 0;
}
@Override
public void run() {
synchronized (this){
for (int i =0; i< 5;i++){
try {
System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static int getCount() {
return count;
}
}
创建一个对象时,不使用Synchronized
package Synchronized;
public class Demo01 {
public static void main(String[] args) {
Syc syc = new Syc();
Thread thread1 = new Thread(syc,"t1");
Thread thread2 = new Thread(syc,"t2");
thread1.start();
thread2.start();
}
}
class Syc implements Runnable{
private static int count;
public Syc() {
count = 0;
}
@Override
public void run() {
for (int i =0; i< 5;i++){
try {
System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static int getCount() {
return count;
}
}
Thread2必须等到Thread1执行完毕之后,释放锁,才可以执行并获得这个锁
创建两个对象使用synchronized时
package Synchronized;
public class Demo01 {
public static void main(String[] args) {
Syc syc = new Syc();
Syc syc1 = new Syc();
Thread thread1 = new Thread(syc,"t1");
Thread thread2 = new Thread(syc1,"t2");
thread1.start();
thread2.start();
}
}
class Syc implements Runnable{
private static int count;
public Syc() {
count = 0;
}
@Override
public void run() {
synchronized (this){
for (int i =0; i< 5;i++){
try {
System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static int getCount() {
return count;
}
}
因为创建了两个Syn的对象,两个线程执行的是两个对象的run方法lsynchronized锁定是的this这个对象,这时候因为创建了两个对象会有两把锁,分别锁定thread1和thread2,两把锁互不干扰,所以可以同时执行
当一个线程访问synchronized代码块是,另一个线程访问不带有synchronized时
package Synchronized;
public class Demo02 {
public static void main(String[] args) {
Syc2 syc = new Syc2();
Thread thread1 = new Thread(syc,"t1");
Thread thread2 = new Thread(syc,"t2");
thread1.start();
thread2.start();
}
}
class Syc2 implements Runnable{
private static int count;
public Syc2() {
count = 0;
}
public void add(){
synchronized (this){
for (int i =0; i< 5;i++){
try {
System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void print(){
for (int i =0; i< 5;i++){
try {
System.out.println("线程" + Thread.currentThread().getName() + "," + count);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void run() {
String thraedstr = Thread.currentThread().getName();
if (thraedstr.equals("t1")){
add();
}else if (thraedstr.equals("t2")){
print();
}
}
public static int getCount() {
return count;
}
}
thread1访问带有synchronized代码块时,thread2可以访问不带有synchronied的代码块,不会受到阻塞
修饰一个实例方法
public synchronized void method(){
}
注意:synchronized关键字修饰的方法不能被继承
虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此,synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。这两种方式的例子代码如下:
在子类方法中加上synchronized关键字
class Parent {
public synchronized void method() { }
}
class Child extends Parent {
public synchronized void method() { }
}
class Parent {
public synchronized void method() { }
}
class Child extends Parent {
public void method() { super.method(); }
}
定义接口时不能使用Synchronized
构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。
修饰一个静态方法
public synchronized static void method(){
}
使用synchronized时
package Synchronized;
public class Demo03 {
public static void main(String[] args) {
Syn3 syn3 = new Syn3();
Thread thread1 = new Thread(syn3,"t1");
Thread thread2 = new Thread(syn3,"t2");
thread1.start();
thread2.start();
}
}
class Syn3 implements Runnable{
private static int count;
public Syn3() {
count =0;
}
public static int getCount() {
return count;
}
public synchronized static void add(){
for (int i =0; i< 5; i++){
try {
System.out.println("线程" + Thread.currentThread().getName() + "," + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void run() {
add();
}
}
Thread1和Thread2是Syn3的两个线程,但在thread1和thread2并发执行时却保持了线程同步。这是因为run中调用了静态方法method,而静态方法是属于类的,所以Thread1和Thread2相当于用了同一把锁。这与使用关键字synchronized运行结果相同
修饰一个类
class ClassN {
public void method() {
synchronized(ClassN.class) {
}
}
}
package Synchronized;
import java.util.ArrayList;
import java.util.List;
public class Demo04 {
public static void main(String[] args) {
Sync sync = new Sync();
Thread thread1 = new Thread(sync, "Thread1");
Thread thread2 = new Thread(sync, "Thread2");
thread1.start();
thread2.start();
}
}
class Sync implements Runnable {
private static int count;
public Sync() {
count = 0;
}
public static void method() {
synchronized(Sync.class) {
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public synchronized void run() {
method();
}
}
和静态方法一样,synchronized作用于一个类的时候,是给这个类加了一把锁
总结:
- 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
- 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
- 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制
Synchronized放在不同的位置总结代码
package ThreadExam1;
/*
t2不需要等到t1执行,只有doSome有锁
*/
public class Test01 {
public static void main(String[] args) {
M m = new M();
Thread t1 = new MyThread(m);
Thread t2 = new MyThread(m);
t1.setName("t1");
t2.setName("t2");
t1.start();
try {
Thread.sleep(1000);//保证t1线程先执行
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
class MyThread extends Thread{
private M m;
public MyThread(M m){
this.m = m;
}
public void run(){
if(Thread.currentThread().getName() == "t1"){
m.doSome();
}
if(Thread.currentThread().getName() == "t2"){
m.doOther();
}
}
}
class M {
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");
}
}
package ThreadExam2;
/*
t2需要等t1执行结束,doSome和doOther都是this这把锁
*/
public class Test01 {
public static void main(String[] args) {
M m = new M();
Thread t1 = new MyThread(m);
Thread t2 = new MyThread(m);
t1.setName("t1");
t2.setName("t2");
t1.start();
try {
Thread.sleep(1000);//保证t1线程先执行
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
class MyThread extends Thread{
private M m;
public MyThread(M m){
this.m = m;
}
public void run(){
if(Thread.currentThread().getName() == "t1"){
m.doSome();
}
if(Thread.currentThread().getName() == "t2"){
m.doOther();
}
}
}
class M {
public synchronized void doSome(){//锁 是 this
System.out.println("doSome begin");
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("doSome over");
}
public synchronized void doOther(){//锁 是 this
System.out.println("doOther begin");
System.out.println("doOther over");
}
}
package ThreadExam3;
/*
两个线程对象,所以t2不需要等t1执行
*/
public class Test01 {
public static void main(String[] args) {
M m = new M();
M m1 = new M();
Thread t1 = new MyThread(m);
Thread t2 = new MyThread(m1);
t1.setName("t1");
t2.setName("t2");
t1.start();
try {
Thread.sleep(1000);//保证t1线程先执行
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
class MyThread extends Thread{
private M m;
public MyThread(M m){
this.m = m;
}
public void run(){
if(Thread.currentThread().getName() == "t1"){
m.doSome();
}
if(Thread.currentThread().getName() == "t2"){
m.doOther();
}
}
}
class M {
public synchronized void doSome(){//锁 是 this
System.out.println("doSome begin");
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("doSome over");
}
public synchronized void doOther(){//锁 是 this
System.out.println("doOther begin");
System.out.println("doOther over");
}
}
package ThreadExam4;
/*
静态方法是类锁,所以t2需要等t1执行
*/
public class Test01 {
public static void main(String[] args) {
M m = new M();
M m1 = new M();
Thread t1 = new MyThread(m);
Thread t2 = new MyThread(m1);
t1.setName("t1");
t2.setName("t2");
t1.start();
try {
Thread.sleep(1000);//保证t1线程先执行
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
class MyThread extends Thread{
private M m;
public MyThread(M m){
this.m = m;
}
public void run(){
if(Thread.currentThread().getName() == "t1"){
m.doSome();
}
if(Thread.currentThread().getName() == "t2"){
m.doOther();
}
}
}
class M {
public synchronized static void doSome(){//锁 是 this
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(){//锁 是 this
System.out.println("doOther begin");
System.out.println("doOther over");
}
}
m.doSome();
}
if(Thread.currentThread().getName() == "t2"){
m.doOther();
}
}
}
class M {
public synchronized static void doSome(){//锁 是 this
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(){//锁 是 this
System.out.println("doOther begin");
System.out.println("doOther over");
}
}