2.2.7 임의의 대상을 대상 모니터로 삼다
앞에서 학습한 바와 같이synchronized(this) 형식의 동기화 코드 블록을 사용하는데 사실 자바는'임의의 대상'을'대상 감청기'로 동기화하는 기능을 지원한다.이 '임의의 대상' 은 대부분 실례 변수와 방법의 매개 변수이며,synchronized (비this 대상) 형식을 사용합니다.
앞에서 synchronized(this) 동기화 코드 블록의 역할에 대한 정리를 통해 알 수 있듯이synchronized(비this 대상) 형식의 역할은 1가지에 불과하다.synchronized(비this 대상 x) 동기화 코드 블록의 코드
'대상 모니터' 를 같은 대상으로 가지고 있는 전제에서 같은 시간에 한 라인만synchronized (비this 대상 x) 동기화 코드 블록의 코드를 실행할 수 있습니다.
/**
* @author wuyoushan
* @date 2017/4/10.
*/
public class Service {
private String usernameParam;
private String passwordParam;
private String anyString=new String();
public void setUsernamePassword(String username,String password) {
try{
synchronized (anyString){
System.out.println(" :"+Thread.currentThread().getName()
+" "+System.currentTimeMillis()+" ");
usernameParam=username;
Thread.sleep(3000);
passwordParam=password;
System.out.println(" :"+Thread.currentThread().getName()
+" "+System.currentTimeMillis()+" ");
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
/**
* @author wuyoushan
* @date 2017/4/4.
*/
public class ThreadA extends Thread{
private Service service;
public ThreadA(Service service){
super();
this.service=service;
}
@Override
public void run() {
service.setUsernamePassword("a","aa");
}
}
/**
* @author wuyoushan
* @date 2017/4/4.
*/
public class ThreadB extends Thread{
private Service service;
public ThreadB(Service service){
super();
this.service=service;
}
@Override
public void run() {
service.setUsernamePassword("b","bb");
}
}
/**
* @author wuyoushan
* @date 2017/3/20.
*/
public class Run {
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 1492391031020
:A 1492391034020
username:a password:aa
:B 1492391034020
:B 1492391037020
username:b password:bb
자물쇠 비this 대상은 일정한 장점을 가진다. 만약에 한 종류에 많은synchronized 방법이 있다면 이것은 동기화를 실현할 수 있으나 막히기 때문에 운행 효율에 영향을 미친다.그러나 동기화 코드 블록 자물쇠가 this 대상이 아니라면synchronized(비this) 코드 블록의 프로그램과 동기화 방법은 비동기적이며 다른 자물쇠this 동기화 방법과 this 자물쇠를 다투지 않으면 운영 효율을 크게 높일 수 있다.
서비스java 파일 코드는 다음과 같이 변경되었습니다.
/**
* @author wuyoushan
* @date 2017/4/10.
*/
public class Service {
private String usernameParam;
private String passwordParam;
public void setUsernamePassword(String username,String password) {
try{
String anyString=new String();
synchronized (anyString){
System.out.println(" :"+Thread.currentThread().getName()
+" "+System.currentTimeMillis()+" ");
usernameParam=username;
Thread.sleep(3000);
passwordParam=password;
System.out.println(" :"+Thread.currentThread().getName()
+" "+System.currentTimeMillis()+" ");
System.out.println("username:"+usernameParam+" password:"+passwordParam);
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
프로그램 실행 결과는 다음과 같습니다.
:A 1492474468701
:B 1492474468702
:A 1492474471702
username:b password:aa
:B 1492474471702
username:b password:bb
"synchronized (비this 대상 x) 동기화 코드 블록"형식으로 동기화 작업을 할 때 대상 모니터는 같은 대상이어야 합니다.같은 대상 모니터가 아니라면 실행 결과가 비동기적으로 호출되면 교차 운행된다.
다음은'synchronized(비this 대상 x) 동기화 코드 블록'형식을 사용할 때 서로 다른 대상 감청기를 가지고 있을 때 다른 효과가 있는지 다른 항목으로 검증해 보겠습니다.
/**
* @author wuyoushan
* @date 2017/4/10.
*/
public class Service {
private String anyString=new String();
public void a() {
try{
synchronized (anyString){
System.out.println("a begin");
Thread.sleep(3000);
System.out.println("a end");
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
synchronized public void b() {
System.out.println("b begin");
System.out.println("b end");
}
}
/**
* @author wuyoushan
* @date 2017/4/4.
*/
public class ThreadA extends Thread{
private Service service;
public ThreadA(Service service){
super();
this.service=service;
}
@Override
public void run() {
service.a();
}
}
/**
* @author wuyoushan
* @date 2017/4/4.
*/
public class ThreadB extends Thread{
private Service service;
public ThreadB(Service service){
super();
this.service=service;
}
@Override
public void run() {
service.b();
}
}
/**
* @author wuyoushan
* @date 2017/3/20.
*/
public class Run {
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 begin
b begin
b end
a end
대상 모니터가 다르기 때문에 실행 결과는 비동기적이다.동기화 코드 블록은 비동기화synchronized 방법에 놓고 설명할 수 있으며 호출 방법의 루틴 실행 동기화/순서성을 보장할 수 없다. 즉, 루틴 호출 방법의 순서는 무질서하다. 비록 동기화 코드 블록에서 실행되는 순서가 동기화되지만 이렇게 하면'더럽히기'문제가 발생하기 쉽다.
'synchronized(비this 대상 x) 동기화 코드 블록'형식을 사용해도'더러운 읽기'문제를 해결할 수 있습니다.그러나 더러운 읽기 문제를 해결하기 전에 먼저 하나의 실험을 하고 실험의 목표는 여러 개의 라인이 같은 방법을 랜덤으로 호출하는 것을 검증하는 것이다.
/**
* @author wuyoushan
* @date 2017/2/5.
*/
public class MyList{
private List list=new ArrayList();
synchronized public void add(String username){
System.out.println("ThreadName="+Thread.currentThread().getName()
+" add ");
list.add(username);
System.out.println("ThreadName="+Thread.currentThread().getName()
+" add ");
}
synchronized public int getSize(){
System.out.println("ThreadName="+Thread.currentThread().getName()
+" getSize ");
int sizeValue=list.size();
System.out.println("ThreadName="+Thread.currentThread().getName()
+" getSize ");
return sizeValue;
}
}
/**
* @author wuyoushan
* @date 2017/2/5.
*/
public class ThreadA extends Thread{
private MyList list;
public ThreadA( MyList list) {
super();
this.list = list;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
list.add("threadA"+(i+1));
}
}
}
/**
* @author wuyoushan
* @date 2017/2/5.
*/
public class ThreadB extends Thread {
private MyList list;
public ThreadB( MyList list) {
super();
this.list = list;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
list.add("threadA"+(i+1));
}
}
}
/**
* @author wuyoushan
* @date 2017/2/5.
*/
public class Run {
public static void main(String[] args) {
MyList myList=new MyList();
ThreadA a=new ThreadA(myList);
a.setName("A");
a.start();
ThreadB b=new ThreadB(myList);
b.setName("B");
b.start();
}
}
프로그램이 실행된 결과는 다음과 같습니다.
ThreadName=B add
ThreadName=B add
ThreadName=A add
ThreadName=A add
ThreadName=B add
ThreadName=B add
실행 결과를 보면 동기화 코드 블록의 코드는 동기화되어 인쇄되고 현재 라인의 '실행' 과 '종료' 는 쌍으로 나타납니다.그러나 스레드 A와 스레드 B의 집행은 비동기적이어서 더러운 읽기 환경이 나타날 수 있다.스레드 실행 방법의 순서가 확실하지 않기 때문에 A와 B 두 스레드가 지점 판단을 가진 방법을 실행할 때 논리적인 오류가 발생하고 더러운 읽기가 발생할 수 있다.
/**
* @author wuyoushan
* @date 2017/4/19.
*/
public class MyOneList {
private List list=new ArrayList<>();
synchronized public void add(String data){
list.add(data);
}
synchronized public int getSzie(){
return list.size();
}
}
/**
* @author wuyoushan
* @date 2017/4/19.
*/
public class MyService {
public MyOneList addServiceMethod(MyOneList list,String data){
try{
if(list.getSzie()<1){
Thread.sleep(2000); // 2
list.add(data);
}
}catch (InterruptedException e){
e.printStackTrace();
}
return list;
}
}
/**
* @author wuyoushan
* @date 2017/4/4.
*/
public class ThreadA extends Thread{
private MyOneList list;
public ThreadA(MyOneList list){
super();
this.list=list;
}
@Override
public void run() {
MyService service=new MyService();
service.addServiceMethod(list,"A");
}
}
/**
* @author wuyoushan
* @date 2017/4/4.
*/
public class ThreadB extends Thread{
private MyOneList list;
public ThreadB(MyOneList list){
super();
this.list=list;
}
@Override
public void run() {
MyService service=new MyService();
service.addServiceMethod(list,"B");
}
}
/**
* @author wuyoushan
* @date 2017/3/20.
*/
public class Run {
public static void main(String[] args) throws InterruptedException {
MyOneList list=new MyOneList();
ThreadA a=new ThreadA(list);
a.setName("A");
a.start();
ThreadB b=new ThreadB(list);
b.setName("B");
b.start();
Thread.sleep(6000);
System.out.println("listSize="+list.getSzie());
}
}
프로그램 실행 후 결과는 다음과 같습니다.
listSize=2
더러운 독서가 나타났다.두 라인이list 매개 변수의 크기 () 크기를 비동기적으로 되돌려주기 때문입니다.그 해결책은 My Service를 동기식으로 변경하는 것입니다.java 클래스 파일 코드:
/**
* @author wuyoushan
* @date 2017/4/19.
*/
public class MyService {
public MyOneList addServiceMethod(MyOneList list,String data){
try{
synchronized (list) {
if (list.getSzie() < 1) {
Thread.sleep(2000); // 2
list.add(data);
}
}
}catch (InterruptedException e){
e.printStackTrace();
}
return list;
}
}
list 매개 변수의 대상은 프로젝트에서 하나의 실례이고 하나의 예이기 때문에list 매개 변수의 getsize () 방법을 동기화해서 호출해야 하기 때문에list 매개 변수를 동기화 처리합니다.프로그램 실행 결과는 다음과 같습니다.
listSize=1
자바 다중 루틴 핵심 프로그래밍 기술 -2.2.7에서 발췌
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.