java 다중 스레드 - 두 가지 실제 응용 장면 시뮬레이션
13704 단어 java 다중 스레드
(1)
먼저 첫 번째, 정보에 대한 발송과 수신을 시뮬레이션합니다.장면은 다음과 같습니다.
필자가 이전에 한 메시지의 발송과 같이 하나는 서버이고 하나는 클라이언트이다.발송하면 정보가 100% 클라이언트에게 발송되는 것을 보증해야 한다. 그러면 클라이언트에게 보낸 후에 클라이언트는 서버에 메시지를 반환하여 이미 받았다고 알려준다.서버가 클라이언트가 되돌아오는 메시지를 받지 못하면 서버는 이 메시지를 계속 보내고 클라이언트가 확인 메시지를 보낼 때까지 이 메시지를 삭제합니다.
이 장면을 모의하기 위해 여기에 두 개의 라인을 쓴다. 하나는 발송이고 하나는 수신이다. 발송된 정보를 라인 안전의 대상에 저장하여 라인 안전 문제가 발생하지 않도록 해야 한다. 여기는concurrenthashmap을 사용한다.
코드 보내기:
package com.TestThread;
/*
*
* @author
*
* */
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
public class PushThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
try {
sleep(6000);
while(MainThread.pushmessage.size()>0){
//
for(Entry<Integer, String> hashMap:MainThread.pushmessage.entrySet()){
System.out.println(" id:"+hashMap.getKey()+" , :"+hashMap.getValue());
}
sleep(1000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
코드를 보내는 것은 메모리 대상인councurrenthashmap을 끊임없이 훑어보면서 정보를 추출하고 재발급합니다.여기서 MainThread.pushmessage는 메모리 대상으로 마지막 코드에 정의되어 있습니다.
정보를 받은 것을 확인한 후, 메모리 대상을 삭제하는 다른 라인이 있습니다.
삭제된 코드:
package com.TestThread;
/*
*
* @author
*
* */
import java.util.Map.Entry;
public class RemoveThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
try {
for (int i = 0; i < 10000; i++) {
sleep(2000);
for(Entry<Integer, String> map:MainThread.pushmessage.entrySet()){
if (map.getKey()==i) {
System.out.println(" id :"+map.getKey()+" , ");
MainThread.pushmessage.remove(map.getKey());
}
}
System.out.println(" :"+MainThread.pushmessage.size());
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
받은 정보를 삭제하고 메모리에서 삭제하고 더 이상 보내지 않습니다.
그런 다음 마스터 클래스 포털을 작성합니다.
package com.TestThread;
/*
*
* @author
*
* */
import java.util.concurrent.ConcurrentHashMap;
public class MainThread {
public static ConcurrentHashMap<Integer, String> pushmessage=new ConcurrentHashMap<Integer,String>();
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
pushmessage.put(i, " id "+i+" ");
}
Thread pushThread=new PushThread();
Thread remove=new RemoveThread();
pushThread.start();
remove.start();
for (int i = 10; i < 20; i++) {
pushmessage.put(i, " , id "+i+" ");
}
}
}
이렇게 하면 두 라인이 돌아가며 각자의 일을 진행할 수 있을 뿐만 아니라 데이터 안전에 문제를 일으키지 않을 것이다.이런 방식으로 안드로이드pn의 전송 메커니즘을 결합하면 실제 생산에서의 응용에 더욱 부합될 것이다.
(2) 다중 스레드 동기화 계수기
다중 스레드 동기화 계수기는 이치에 따라 위의 방식에 따라 처리할 수 있으며,concurrenthashmap과 같은 변수를 정의할 수 있다.자바에도 원자 변수인 Atomic, Atomic Long, Atomic Integer, Atomic Reference 등 다른 변수가 있다.
만약 다중 스레드 환경에서 일부 값에 유일한 id를 부여해야 한다면 이때 이 id의 안전성 문제, 즉 일치성을 고려해야 하며 중복해서는 안 된다.여기에는 두 개의 실현 코드가 있다.
package com.test;
public class ThreadCount {
public static void main(String[] args) {
Thread[] threads=new Thread[10000];
for (int i = 0; i < 10000; i++) {
threads[i]=new AThread();
threads[i].start();
}
}
}
class AThread extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
@SuppressWarnings("unused")
Counter counter=new Counter();
System.out.println(Counter.calNum());
}
}
class Counter{
private static long num;
public Counter(){
synchronized (Counter.class) {
num++;
}
}
public static synchronized long calNum(){
return num;
}
}
여기에 10000개의 라인을 만들었습니다. 모든 라인이 이 계수기에 접근하여 구조 방법에서 값을 점차적으로 증가시킵니다.
계수기에서 두 번이나 동기화를 사용했는데 많은 사람들이 동기화를 사용하면 성능에 영향을 미친다고 말한다.그래서 두 번째 원자 변수를 사용하면 이 성능이 더욱 좋아질 것이다.
코드:
package com.test;
import java.util.concurrent.atomic.AtomicLong;
public class ThreadCount {
public static void main(String[] args) {
Thread[] threads=new Thread[10000];
for (int i = 0; i < 10000; i++) {
threads[i]=new AThread();
threads[i].start();
}
}
}
class AThread extends Thread{
@Override
public void run() {
System.out.println(MyCounter.calNum());
}
}
class Counter{
private static long num;
public Counter(){
synchronized (Counter.class) {
num++;
}
}
public static synchronized long calNum(){
return num;
}
}
class MyCounter{
private static AtomicLong num=new AtomicLong();
public static synchronized long calNum(){
return num.incrementAndGet();
}
}
이렇게 쓰면 이 계수기를 호출할 때 MyCounter 대상을 새로 만들 필요가 없습니다.
이렇게 하면 도구 클래스로 MyCounter의calNum 방법을 직접 호출할 수 있다.