java5 of thread concurrency library - a set of synchronous

1. The queue may be blocked --BlockingQueue

        Queue comprising queues of fixed length and fixed length not.

        BlockingQueue is an interface, which supports two additional operations Queue, these two operations are: queue becomes non-empty, the storage element and wait for space to become available when acquiring element.

1.1 API

1.1.1 insert

1. add (e): the time when the queue is full, it will add a Throws

2. offer (e): If the queue is full, with a time offer added returns false.

3. put (e): If the queue is full, with the time to put added, the program will block until it can be inserted so far.

4. offer(e,time,unit)

1.1.2 removed

1. remove (): When the queue is empty, with the exception thrown will remove

2. poll (): When the queue is empty, when a poll will return null

3. take (): When the queue is empty, the program will take a block until the queue is not empty so far.

4. poll(time,unit)

1.1.3 inspection

1. element (): Get, but does not remove the head of this queue, it will throw an exception when the queue is empty

2. peek (): Get but does not remove the head of this queue; if this queue is empty, null is returned.

E.g:

package com.bjc.thread.demo6;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueTest {
	public static void main(String[] args) {
		final BlockingQueue queue = new ArrayBlockingQueue(3);
		for(int i=0;i<2;i++){
			new Thread(){
				public void run(){
					while(true){
						try {
							Thread.sleep((long)(Math.random()*1000));
							System.out.println(Thread.currentThread().getName() + "准备放数据!");							
							queue.put(1);
							System.out.println(Thread.currentThread().getName() + "已经放了数据," + 							
										"队列目前有" + queue.size() + "个数据");
						} catch (InterruptedException e) {
							e.printStackTrace();
						}

					}
				}
				
			}.start();
		}
		
		new Thread(){
			public void run(){
				while(true){
					try {
						//将此处的睡眠时间分别改为100和1000,观察运行结果
						Thread.sleep(1000);
						System.out.println(Thread.currentThread().getName() + "准备取数据!");
						queue.take();
						System.out.println(Thread.currentThread().getName() + "已经取走数据," + 							
								"队列目前有" + queue.size() + "个数据");					
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
		}.start();			
	}
}

1.2 simple application blocking queue

1. two queues having a space to implement the functions of the sync notifications.

Business.java

package com.bjc.thread.demo6;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * 思路:
 * 		1. 创建两个长度为1的阻塞队列
 * 		2. 默认让队列2为满队列
 * 		3. 通过阻塞队列的API的可阻塞方法来实现线程的通信
 *
 */
public class Business {
	private BlockingQueue<Integer> q1 = new ArrayBlockingQueue<Integer>(1);
	private BlockingQueue<Integer> q2 = new ArrayBlockingQueue<Integer>(1);
	
	// 可以理解为匿名的构造函数,该代码块先于构造函数执行
	{
		try {
			// 创建对象的时候,让q2队列为满队列
			q2.put(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public void sub() throws Exception{
		// 往q1队列放入元素
		q1.put(1);
		for(int i = 0 ; i < 3; i++){
			System.out.println("          sub");
		}
		// q2队列取出元素
		q2.take();
	}
	
	public void main() throws Exception{
		// 往q2队列放入元素
		q2.put(1);
		for(int i = 0 ; i < 5; i++){
			System.out.println("main");
		}
		// q1队列取出元素
		q1.take();
	}
	
}

Test Methods:

package com.bjc.thread.demo6;

public class BlockingQueuCom {

	public static void main(String[] args) {
		Business b = new Business();
		new Thread(){
			@Override
			public void run() {
				try {
					for(int i = 0 ; i < 10 ; i++){
						b.sub();
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}.start();
		
		new Thread(){
			@Override
			public void run() {
				try {
					for(int i = 0 ; i < 10 ; i++){
						b.main();
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}.start();
	}
}

operation result:

2. The existing program code to generate a simulated log object 16, needs to run 16 seconds before and after printing the logs, four additional threads in the program to transfer parseLog () method which separately print log object 16, the program only need to run finished 4 seconds to print the log object

package com.bjc.test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @author Administrator
 * 现有的程序代码模拟产生了16个日志对象,并且需要运行16秒才能打印完这些日志,
 * 请在程序中增加4个线程去调用parseLog()方法来分头打印这16个日志对象,
 * 程序只需要运行4秒即可打印完这些日志对象
 * 
 */
public class Demo1 {

	public static void main(String[] args) throws Exception{
		BlockingQueue<String> queue = new ArrayBlockingQueue<String>(4);
		for(int i = 0 ; i < 4 ; i++){
			new Thread(){
				@Override
				public void run() {
					while(true){
						try {
							String log = queue.take();
							parseLog(log);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				};
			}.start();
		}
        
		System.out.println("begin:"+(System.currentTimeMillis()/1000));
		/*模拟处理16行日志,下面的代码产生了16个日志对象,当前代码需要运行16秒才能打印完这些日志。
		修改程序代码,开四个线程让这16个对象在4秒钟打完。
		*/
		for(int i=0;i<16;i++){  //这行代码不能改动
			final String log = ""+(i+1);//这行代码不能改动
			{
				queue.put(log);
			}
		}
	}
	
	//parseLog方法内部的代码不能改动
	public static void parseLog(String log){
		System.out.println(log+":"+(System.currentTimeMillis()/1000));
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}		
	}

}

3. Test class ready-made program code is constantly generated data, and then to TestDo.doSome () method to deal with, if producers continue to produce data, consumers continue to consume data. Please transformed into a program with 10 threads to generate consumption data were generated, these consumers are calling TestDo.doSome () method to be processed, so every consumer need one second to process complete, the program should ensure that these consumer who in turn ordered the thread consumption data, only on a consumer spending after the next consumer to consumer data, the next consumer anyone can, but to ensure that these consumers get the thread data is in order

package com.bjc.test;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;

/**
 * @author Administrator
 * 现成程序中的Test类中的代码在不断地产生数据,然后交给TestDo.doSome()方法去处理,
 * 就好像生产者在不断地产生数据,消费者在不断消费数据。请将程序改造成有10个线程来消费生成者产生的数据,
 * 这些消费者都调用TestDo.doSome()方法去进行处理,故每个消费者都需要一秒才能处理完,
 * 程序应保证这些消费者线程依次有序地消费数据,只有上一个消费者消费完后,下一个消费者才能消费数据,
 * 下一个消费者是谁都可以,但要保证这些消费者线程拿到的数据是有顺序的
 */
public class Demo2 {
	public static void main(String[] args) throws Exception {
		// 定义一个信号量,用于让一次只有一个线程执行
		Semaphore semaphore = new Semaphore(1);
		// 定义一个同步队列
		BlockingQueue<String> queue = new SynchronousQueue<String>();
		for(int i = 0 ; i < 10 ; i++){
			new Thread(){
				@Override
				public void run() {
					try {
						// 获取信号量
						semaphore.acquire();
						String input = queue.take();
						String output = TestDo.doSome(input);
						System.out.println(Thread.currentThread().getName()+ ":" + output);
						// 释放信号量
						semaphore.release();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				};
			}.start();
		}
		System.out.println("begin:"+(System.currentTimeMillis()/1000));
		for(int i=0;i<10;i++){  //这行不能改动
			String input = i+"";  //这行不能改动
			// String output = TestDo.doSome(input);
			queue.put(input);
		}
	}
}

//不能改动此TestDo类
class TestDo {
	public static String doSome(String input){
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		String output = input + ":"+ (System.currentTimeMillis() / 1000);
		return output;
	}
}

4. Existing programs simultaneously started four threads to call TestDo.doSome (key, value) method, the code within the TestDo.doSome (key, value) is 1 second pause, then the output in seconds current time value, it will print the same time the value 4, as shown below:
        4: 4: 1258199615
        1: 1: 1258199615
        3: 3: 1258199615
        1: 2: 1258199615
        modify the code, if there are several thread calls when TestDo.doSome (key, value) method, passing in the key is equal to (comparison of the equals to true), then these threads should exclusive line output, i.e., when each of the two threads key "1", a further than the other threads in their later one second output, as follows:
        4: 4: 1258199615
        1: 1: 1258199615
        3: 3: 1258199615
        1: 2: 1258199616
      summary, when each thread is equal to the specified key when these threads should be equal to the key are sequentially output time value (exclusive use) every second, if a different key, is executed in parallel (to each other is not mutually exclusive)

My problem-solving approach:

package com.bjc.demo3;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

//不能改动此Test类	
	public class Test extends Thread{
		
		private TestDo testDo;
		private String key;
		private String value;
		
		public Test(String key,String key2,String value){
			this.testDo = TestDo.getInstance();
			/*常量"1"和"1"是同一个对象,下面这行代码就是要用"1"+""的方式产生新的对象,
			以实现内容没有改变,仍然相等(都还为"1"),但对象却不再是同一个的效果*/
			this.key = key+key2; 
			this.value = value;
		}


		public static void main(String[] args) throws InterruptedException{
			Test a = new Test("1","","1");
			Test b = new Test("1","","2");
			Test c = new Test("3","","3");
			Test d = new Test("4","","4");
			System.out.println("begin:"+(System.currentTimeMillis()/1000));
			a.start();
			b.start();
			c.start();
			d.start();

		}
		
		public void run(){
			testDo.doSome(key, value);
		}
	}

	class TestDo {

		private TestDo() {}
		private static TestDo _instance = new TestDo();	
		public static TestDo getInstance() {
			return _instance;
		}
		
		private List<Object> list = new ArrayList<Object>();
		public void doSome(Object key, String value) {
			// 注意这里不能仅仅加synchronized同步,因为每次传递过来的key都是不同的对象,所以需要处理
			Object o = key;
			if(!list.contains(o)){
				list.add(key);
			} else {
				// 这里不能用list.indexOf(o)来获取对象的下标,因为多线程的原因,集合的大小会改变
				// 所以这里用迭代器
				while(list.iterator().hasNext()){
					try {
						Thread.sleep(30);
						Object o1 = list.iterator().next();
						if(o1.equals(o)){
							o = o1;
							break;
						}
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			synchronized (o) 
			// 以大括号内的是需要局部同步的代码,不能改动!
			{
				try {
					Thread.sleep(1000);
					System.out.println(key+":"+value + ":"
							+ (System.currentTimeMillis() / 1000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

	}

standard answer:

package syn;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

//不能改动此Test类	
public class Test extends Thread{
	
	private TestDo testDo;
	private String key;
	private String value;
	
	public Test(String key,String key2,String value){
		this.testDo = TestDo.getInstance();
		/*常量"1"和"1"是同一个对象,下面这行代码就是要用"1"+""的方式产生新的对象,
		以实现内容没有改变,仍然相等(都还为"1"),但对象却不再是同一个的效果*/
		this.key = key+key2; 
/*		a = "1"+"";
		b = "1"+""
*/
		this.value = value;
	}


	public static void main(String[] args) throws InterruptedException{
		Test a = new Test("1","","1");
		Test b = new Test("1","","2");
		Test c = new Test("3","","3");
		Test d = new Test("4","","4");
		System.out.println("begin:"+(System.currentTimeMillis()/1000));
		a.start();
		b.start();
		c.start();
		d.start();

	}
	
	public void run(){
		testDo.doSome(key, value);
	}
}

class TestDo {

	private TestDo() {}
	private static TestDo _instance = new TestDo();	
	public static TestDo getInstance() {
		return _instance;
	}

	//private ArrayList keys = new ArrayList();
	private CopyOnWriteArrayList keys = new CopyOnWriteArrayList();
	public void doSome(Object key, String value) {
		Object o = key;
		if(!keys.contains(o)){
			keys.add(o);
		}else{

			for(Iterator iter=keys.iterator();iter.hasNext();){
				try {
					Thread.sleep(20);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				Object oo = iter.next();
				if(oo.equals(o)){
					o = oo;
					break;
				}
			}
		}
		synchronized(o)
		// 以大括号内的是需要局部同步的代码,不能改动!
		{
			try {
				Thread.sleep(1000);
				System.out.println(key+":"+value + ":"
						+ (System.currentTimeMillis() / 1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

Note: The standard answer is CopyOnWriteArrayList concurrent use of container

2. Concurrent collections

 

To be continued. . . . . .

 

 

 

 

 

 

 

 

Published 128 original articles · won praise 6 · views 3223

Guess you like

Origin blog.csdn.net/weixin_43318134/article/details/103811792