Java多线程初学者指南(10):利用Synchronized要害字同步类要领
当前位置:以往代写 > JAVA 教程 >Java多线程初学者指南(10):利用Synchronized要害字同步类要领
2019-06-14

Java多线程初学者指南(10):利用Synchronized要害字同步类要领

Java多线程初学者指南(10):利用Synchronized要害字同步类要领

副标题#e#

要想办理“脏数据”的问题,最简朴的要领就是利用synchronized要害字来使run要领同步,代码如下:

public synchronized void run()
{
Java多线程初学者指南(10):操作Synchronized关键字同步类方式Java多线程初学者指南(10):操作Synchronized关键字同步类方式
}

从上面的代码可以看出,只要在void和public之间加上synchronized要害字,就可以使run要领同步,也就是说,对付同一个Java类的工具实例,run要领同时只能被一个线程挪用,并当前的run执行完后,才气被其他的线程挪用。纵然当前线程执行到了run要领中的yield要领,也只是暂停了一下。由于其他线程无法执行run要领,因此,最终照旧会由当前的线程来继承执行。先看看下面的代码:

sychronized要害字只和一个工具实例绑定

class Test
{
 public synchronized void method()
 {
Java多线程初学者指南(10):操作Synchronized关键字同步类方式Java多线程初学者指南(10):操作Synchronized关键字同步类方式
 }
}

public class Sync implements Runnable
{
 private Test test;
 public void run()
 {
  test.method();
 }
 public Sync(Test test)
 {
  this.test = test;
 }
 public static void main(String[] args) throws Exception
 {
  Test test1 =  new Test();
  Test test2 =  new Test();
  Sync sync1 = new Sync(test1);
  Sync sync2 = new Sync(test2);
  new Thread(sync1).start();
  new Thread(sync2).start(); 
}

在Test类中的method要领是同步的。但上面的代码成立了两个Test类的实例,因此,test1和test2的method要领是别离执行的。要想让method同步,必需在成立Sync类的实例时向它的结构要领中传入同一个Test类的实例,如下面的代码所示:

Sync sync1 = new Sync(test1);

不只可以利用synchronized来同步非静态要领,也可以利用synchronized来同步静态要领。如可以按如下方法来界说method要领:

class Test 
{
 public static synchronized void method() { Java多线程初学者指南(10):操作Synchronized关键字同步类方式Java多线程初学者指南(10):操作Synchronized关键字同步类方式 }
}

成立Test类的工具实譬喻下:

Test test = new Test();


#p#副标题#e#

对付静态要领来说,只要加上了synchronized要害字,这个要领就是同步的,无论是利用test.method(),照旧利用Test.method()来挪用method要领,method都是同步的,并不存在非静态要领的多个实例的问题。

在23种设计模式中的单件(Singleton)模式假如按传统的要领设计,也是线程不安详的,下面的代码是一个线程不安详的单件模式。

package test;

// 线程安详的Singleton模式
class Singleton
{
 private static Singleton sample;

 private Singleton()
 {
 }
 public static Singleton getInstance()
 {
  if (sample == null)
  {
   Thread.yield(); // 为了放大Singleton模式的线程不安详性
   sample = new Singleton();
  }
  return sample;
 }
}
public class MyThread extends Thread
{
 public void run()
 {
  Singleton singleton = Singleton.getInstance();
  System.out.println(singleton.hashCode());
 }
 public static void main(String[] args)
 {
  Thread threads[] = new Thread[5];
  for (int i = 0; i < threads.length; i++)
   threads[i] = new MyThread();
  for (int i = 0; i < threads.length; i++)
   threads[i].start();
 }
}

在上面的代码挪用yield要领是为了使单件模式的线程不安详性表示出来,假如将这行去掉,上面的实现仍然是线程不安详的,只是呈现的大概性小得多。

措施的运行功效如下:

25358555
26399554
7051261
29855319
5383406

上面的运行功效大概在差异的运行情况上有所有同,但一般这五行输出不会完全沟通。从这个输出功效可以看出,通过getInstance要领获得的工具实例是五个,而不是我们期望的一个。这是因为当一个线程执行了Thread.yield()后,就将CPU资源交给了别的一个线程。由于在线程之间切换时并未执行到建设Singleton工具实例的语句,因此,这几个线程都通过了if判定,所以,就会发生了成立五个工具实例的环境(大概建设的是四个或三个工具实例,这取决于有几多个线程在建设Singleton工具之前通过了if判定,每次运行时大概功效会纷歧样)。

要想使上面的单件模式酿成线程安详的,只要为getInstance加上synchronized要害字即可。代码如下:

#p#分页标题#e#

public static synchronized Singleton getInstance() { Java多线程初学者指南(10):操作Synchronized关键字同步类方式Java多线程初学者指南(10):操作Synchronized关键字同步类方式 }

虽然,尚有更简朴的要领,就是在界说Singleton变量时就成立Singleton工具,代码如下:

private static final Singleton sample = new Singleton();

然后在getInstance要领中直接将sample返回即可。这种方法固然简朴,但不知在getInstance要领中建设Singleton工具机动。读者可以按照详细的需求选择利用差异的要领来实现单件模式。

#p#副标题#e#

在利用synchronized要害字时有以下四点需要留意:

1.  synchronized要害字不能担任。

固然可以利用synchronized来界说要领,但synchronized并不属于要领界说的一部门,因此,synchronized要害字不能被担任。假如在父类中的某个要领利用了synchronized要害字,而在子类中包围了这个要领,在子类中的这个要领默认环境下并不是同步的,而必需显式地在子类的这个要领中加上synchronized要害字才可以。虽然,还可以在子类要领中挪用父类中相应的要领,这样固然子类中的要领不是同步的,但子类挪用了父类的同步要领,因此,子类的要领也就相当于同步了。这两种方法的例子代码如下:

在子类要领中加上synchronized要害字

class Parent
{
 public synchronized void method() { Java多线程初学者指南(10):操作Synchronized关键字同步类方式Java多线程初学者指南(10):操作Synchronized关键字同步类方式 }
}
class Child extends Parent
{
 public synchronized void method() { Java多线程初学者指南(10):操作Synchronized关键字同步类方式Java多线程初学者指南(10):操作Synchronized关键字同步类方式 }
}

在子类要领中挪用父类的同步要领

class Parent
{
 public synchronized void method() { Java多线程初学者指南(10):操作Synchronized关键字同步类方式Java多线程初学者指南(10):操作Synchronized关键字同步类方式 }
}
class Child extends Parent
{
 public void method() { super.method();Java多线程初学者指南(10):操作Synchronized关键字同步类方式Java多线程初学者指南(10):操作Synchronized关键字同步类方式 }
}

2.  在界说接口要领时不能利用synchronized要害字。

3.  结构要领不能利用synchronized要害字,但可以利用下节要接头的synchronized块来举办同步。

4.  synchronized可以自由安排。

在前面的例子中利用都是将synchronized要害字放在要领的返回范例前面。但这并不是synchronized可安排独一位置。在非静态要领中,synchronized还可以放在要领界说的最前面,在静态要领中,synchronized可以放在static的前面,代码如下:

public synchronized void method();
synchronized public void method();
public static synchronized void method();
public synchronized static void method();
synchronized public static void method();

但要留意,synchronized不能放在要领返回范例的后头,如下面的代码是错误的:

public void synchronized method();
public static void synchronized method();

synchronized要害字只能用来同步要领,不能用来同步类变量,如下面的代码也是错误的。

public synchronized int n = 0;
public static synchronized int n = 0;

#p#副标题#e#

固然利用synchronized要害字同步要领是最安详的同步方法,但大量利用synchronized要害字会造成不须要的资源耗损以及机能损失。固然从外貌上看synchronized锁定的是一个要领,但实际上synchronized锁定的是一个类。也就是说,假如在非静态要领method1和method2界说时都利用了synchronized,在method1未执行完之前,method2是不能执行的。静态要领和非静态要领的环境雷同。但静态和非静态要领不会相互影响。看看如下的代码:

#p#分页标题#e#

package test;

public class MyThread1 extends Thread
{
 public String methodName;

 public static void method(String s)
 {
  System.out.println(s);
  while (true)
            ;
 }
 public synchronized void method1()
 {
  method("非静态的method1要领");
 }
 public synchronized void method2()
 {
  method("非静态的method2要领");
 }
 public static synchronized void method3()
 {
  method("静态的method3要领");
 }
 public static synchronized void method4()
 {
  method("静态的method4要领");
 }
 public void run()
 {
  try
  {
   getClass().getMethod(methodName).invoke(this);
  }
  catch (Exception e)
  {
  }
 }
 public static void main(String[] args) throws Exception
 {
  MyThread1 myThread1 = new MyThread1();
  for (int i = 1; i <= 4; i++)
  {
   myThread1.methodName = "method" + String.valueOf(i);
   new Thread(myThread1).start();
   sleep(100);
  }
 }
}

运行功效如下:

非静态的method1要领

静态的method3要领

从上面的运行功效可以看出,method2和method4在method1和method3未竣事之前不能运行。因此,我们可以得出一个结论,假如在类中利用synchronized要害字来界说非静态要领,那将影响这其中的所有利用synchronized要害字界说的非静态要领。假如界说的是静态要领,那么将影响类中所有利用synchronized要害字界说的静态要领。这有点象数据表中的表锁,当修改一笔记录时,系统就将整个表都锁住了,因此,大量利用这种同步方法会使措施的机能大幅度下降。

    关键字:

在线提交作业