Java 学习笔记——线程

1. 线程的状态

2. 线程实现的两种方式
2.1 实现 Runnable 接口

class MyRunnable implements Runnable {

	@Override
	public void run() {
		// do something
	}
}

Thread t = new Thread(new Runnable());  //创建线程对象
t.start()  //启动线程
2.2 继承 Thread 类
class MyThread extends Thread {

	@Override
	public void run() {
		// do something
	}
}

MyThread mt = new MyThread();  //创建线程对象
mt.start();  //启动线程
3. 线程的同步
3.1 ReentrantLock 锁对象
class Bank {
	private Lock myLock = new ReentrantLock(); //创建 ReentrantLock 锁对象
	
	public void m() {
		myLock.lock();
		try{
			// critical section
		}finally{
			myLock.unlock();
		}
	}
}
    这个结构确保任何时刻只有一个线程进入临界区。当其它线程调用 lock 时,它们会被阻塞,直到第一个线程释放锁对象。
    线程在每次调用 lock 方法前,都会调用 unlock 方法释放锁,所以被一个锁保护的代码可以调用另一个使用相同锁的方法。

3.2 条件对象 Condition

class Bank {
	private final double[] accounts;
	private Lock bankLock = new ReentrantLock();
	private Condition sufficientFunds;
	
	public Bank(int n, double initialBalance) {
		sufficientFunds = bankLock.newCondition();  //获取条件对象
		accounts = new double[n];
		for (int i = 0; i < accounts.length; i ++) {
			accounts[i] = initialBalance;
		}
	}
	
	public void transfer(int from, int to, double amount) throws InterruptedException {
		bankLock.lock();
		try {
			while(accounts[from] < amount) {
				sufficientFunds.wait();  //设置当前线程由于该条件(condition)而处于阻塞状态,并释放锁
			}
			System.out.print(Thread.currentThread());
			accounts[from] -= amount;
			System.out.printf("%10.2f from %d to %d", amount, from, to);
			accounts[to] += amount;
			System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
			sufficientFunds.signalAll(); //在当前线程完成后,调用同一 condition 上的 signAll() 方法,重新激活因为这个条件(condition)而等待的所有线程
		} finally {
			bankLock.unlock();
		}
	}
}
3.3 synchronized 实现内部锁
public synchronized void transfer(int from, int to, double amount) throws InterruptedException {
		while(accounts[from] < amount) {
			wait();  //相当于 condition.wait()
		}
		System.out.print(Thread.currentThread());
		accounts[from] -= amount;
		System.out.printf("%10.2f from %d to %d", amount, from, to);
		accounts[to] += amount;
		System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
		notifyAll();  //相当于 condition.signAll()
}
3.4 Volatile 域
public volatile static boolean done;
3.5 死锁
    所有的线程都被阻塞,都在等待资源被释放
3.6 ThreadLocal 设置线程局部变量
public class ThreadStudy{
	public static final ThreadLocal<SimpleDateFormat> dateFormat;

	static {
		dateFormat = new ThreadLocal<SimpleDateFormat>() {
			protected SimpleDateFormat initialValue() { //初始化线程局部变量
				return new SimpleDateFormat("yyyy-MM-dd");
			}
		};
	}

	@Test
	public void testTreadLocal() {
		//在一个给定线程中,首次调用 get()时,会调用 initialValue(),然后 get() 方法会返回属于当前线程变量的实例
		String date = dateFormat.get().format(new Date()); 
		System.out.println(date);
	}

}
3.7 读写锁
class bank {
	private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); //创建读写锁对象
	private Lock readLock = rwl.readLock();  //获取读锁
	private Lock writeLock = rwl.writeLock();  //获取写锁

	//为读取数据方法添加 read loc	
	public double getTotalBalance() {
		readLock.lock();
		try {
			// ...
		} finally {
			readLock.unlock();
		}
	}
	//为修改数据的方法添加 write lock
	public void transfer() {
		writeLock.lock();
		try{
			//...
		} finally { writeLock.unlock(); }
	}
}

4. 线程安全的集合
4.1 高效的映射表、集合和队列
    java.util.concurrent 包提供了映射表、有序集合队列的高效实现:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet 和 ConcurrentLinkedQueue
4.2 CopyOnWriteArrayList 和 CopyOnWriteArraySet
    任何集合类都可以通过 Collections 类的线程同步包装方法实现线程安全。

List<E> synchArrayList = Collections.synchronizedList(new ArrayList<E>());
Map<K,V> synchHashMap = Collections.synchronizedMap(new HashMap<k,V>);

    最好使用 java.util.concurrent 包中定义的集合,不使用同步包装器中的。特别是假如它们被访问的是不同的桶,由于 ConcurrentHashMap 已经精心的实现了,多线程可以访问它而且不会彼此阻塞。有一个例外是经常被修改的数组列表,在那种情况下,同步的 ArrayList 可以胜过 CopyOnWriteArrayList

5. Callable 和 Future
    Callable 和 Runnable 类似,但是 Callable 有返回值,返回值类型是 Callable 的类型参数

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}
    Future 类用来保存异步计算的结果,FutureTask 是 Future 和 Runnable 接口的实现类,可以把 Callable 转换成 Future 和 Runnable
Callable<Integer> myComputation = ...;
FutureTask<Integer> task = new FutureTask<Integer>(myComputation);
Thread t = new Thread(task);  // it's a Runnable
t.start();
Integer result = task.get();  // it's a Future
6. 执行器 Executor
6.1 线程池   
    构建一个新的线程是有代价的,因为涉及与操作系统的交互。如果程序中创建了大量的生命周期很短的线程,就应该使用线程池,它包含许多准备运行的空线程。
在使用线程池时应该做的步骤:
    调用 Executors 类的静态方法 newCachedThreadPool 或 newFixedThreadPool,创建线程池;
    调用 submit 方法提交 Runnable 或 Callable 对象;
    保存 submit 方法返回的 Future 对象,如果需要取消任务或者别的对异步计算任务的操作;
    当不提交任何任务时调用 shutdown;
		//如果没有现有的线程将会创建新线程,否则会重用以前构建的线程,空闲线程会被保留60s后从缓存中移除
		//这些池通常会提高执行许多生命周期短的异步任务程序的性能。
		ExecutorService pool = Executors.newCachedThreadPool();
		
		//创建一个固定线程数的线程池,池中的线程一直都存在,直到它被关闭
		//ExecutorService pool2 = Executors.newFixedThreadPool(10);
		
		//调用 submit 方法提交 Runnable 或 Callable 对象
		Future<?> result = pool.submit(new Runnable() {
			@Override
			public void run() {
				// do something...
				System.out.println("runnable......");
			}
		});
		
		result = pool.submit(new Callable<Integer>() {
			@Override
			public Integer call() throws Exception {
				System.out.println("callable......");
				return 0;
			}			
		});
		
		try {
			result.get();  //获取异步执行的结果
			//result.cancel(true); //取消这个任务
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
		
		//获取线程池中最大的线程数
		((ThreadPoolExecutor) pool).getLargestPoolSize();
		
		//当不再提交任何任务时,调用 shutdown
		pool.shutdown();
6.2 预定执行 ScheduledExecutorService
     ScheduleExecutorService 接口具有为预定执行和重复周期性执行任务而设计的方法。


		//返回一个线程池,它使用指定的线程数来调度任务
		ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);
		
		//预定在指定的时间之后执行任务
		ScheduledFuture<Integer> sfuture = pool.schedule(new Callable<Integer>() {
			@Override
			public Integer call() throws Exception {
				// TODO Auto-generated method stub
				return 0;
			}
		}, 1000, TimeUnit.MILLISECONDS);
6.3 控制任务组 ExecutorCompletionService<V>
	public void testExecutorCompletionService()  throws Exception{
		//设置需要执行的任务数组
		List<Callable<Integer>> tasks = new ArrayList<>();
		tasks.add(new Callable<Integer>() {
			@Override
			public Integer call() {
				System.out.println(0);
				return 0;
			}
		});
		tasks.add(new Callable<Integer>() {
			@Override
			public Integer call() {
				System.out.println(1);
				return 1;
			}
		});

		//创建线程池
		ExecutorService pool = Executors.newCachedThreadPool();
		//创建一个 ExecutorCompletionService 来收集给定执行器的结果
		ExecutorCompletionService<Integer> service = new ExecutorCompletionService<>(pool);
		
		for (Callable<Integer> task : tasks) {
			service.submit(task); //提交任务给 executor 执行
		}
		
		for (int i = 0; i< tasks.size(); i ++) {
			Future<?> f = service.take(); //返回并移除下一个已完成的任务,如果没有任何已完成的结果可用,则阻塞
			System.out.println(f.get());
		}
	}
6.4 Fork-Join
    Fork-Join 框架是 Java7 提供的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。
public void testForkJoin() {
	final int SIZE = 10000000;
	double[] numbers = new double[SIZE];
	for (int i = 0; i < SIZE; i++) {
		numbers[i] = Math.random();
	}
	Counter counter = new Counter(numbers, 0, numbers.length, new Filter() {
		public boolean accept(double x) {
			return x > 0.5;
		}
	});
	ForkJoinPool pool = new ForkJoinPool(); // An ExecutorService for running ForkJoinTasks
	pool.invoke(counter);
	System.out.println(counter.join());
}

interface Filter {
	boolean accept(double t);
}

class Counter extends RecursiveTask<Integer> {
	/**
	 * 
	 */
	private static final long serialVersionUID = 6015924121619834142L;
	
	public static final int THRESHOLD = 1000;
	private double[] values;
	private int from;
	private int to;
	private Filter filter;

	public Counter(double[] values, int from, int to, Filter filter) {
		this.values = values;
		this.from = from;
		this.to = to;
		this.filter = filter;
	}

	protected Integer compute() {
		if (to - from < THRESHOLD) {
			int count = 0;
			for (int i = from; i < to; i++) {
				if (filter.accept(values[i]))
					count++;
			}
			return count;
		} else {
			int mid = (from + to) / 2;
			Counter first = new Counter(values, from, mid, filter);
			Counter second = new Counter(values, mid, to, filter);
			invokeAll(first, second);
			return first.join() + second.join();
		}
	}
}	


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值