java核心技术(8)多线程
1、在一个单独的线程中执行一个任务的简单过程:
1)写一个实现了Runnable接口的类,将操作写在run方法中
public class MyRunnable implements Runnable { @Override public void run() { task code } }
2)、创建一个类对象
Runnable mr = new MyRunnable();
3)、由Runnable创建一个Thread对象;
Thread t = new Thread(mr);
4)、启动线程
t.start();
2、获取当前线程:
Thread.currentThread();
获取线程状态:getState();
3、线程状态:
1)新建 使用new操作符创建一个时
2)可运行 调用start之后,处于可运行状态的线程可能正在运行,也可能没有运行,所以称为可运行
3)被阻塞(被动)和等待(主动)状态,
4)终止(正常运行结束或者异常终止)
4、同步:两种方式:
1)Lock/Condition(可多条件)
//private Lock testLock; //private Condition sfficientFunds; //testLock = new ReentrantLock(); //sufficientFunds = testLock.newCondition(); public void test() { testLock.lock(); try { while(condition) { sfficientFunds.wait(); } task code...... sfficientFunds.signalAll(); } finally { testLock.unlock(); } }
2)synchronized关键字(内部锁和一个相关条件)
public synchronized void test() { while(condition) { wait(); } task code...... notifyAll(); }
3、免锁机制:
volatile关键字,提供一种免锁机制,但是编译器和虚拟机知道该域可能被另一个线程并发更新。
确保域并发访问时安全的三种方式:
1)域是final的,并且在构造器调用完成之后被访问
2)对域的访问由公有的锁进行保护
3)域是volatile的
4、使用队列实现同步
5、线程安全的集合:
6、两种方式使用线程安全的集合:
1)、使用java提供的线程安全的集合,如:
(1)其中Vector、HashTable、Properties是线程安全的。
(2)另外java.util.concurrent 包下提供了大量支持高效并发访问的集合接口和实现类:
- 以Concurrent 开头的集合类,如ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentLinkedQueue 和 ConcurrentLinkedDeque。
- 以CopyOnWrite 开头的集合类,如CopyOnWriteArrayList、CopyOnWriteArraySet。
2)、使用同步包装器:
Collections提供的类方法把这些集合包装成线程安全的集合。Collections提供了如下几个静态方法。
- <T> Collection<T> synchronizedCollection(Collection<T> c): 返回指定collection 对应的线程安全的collection。
- static <T> List<T> synchronizedList(List<T> list): 返回指定List对象对应的线程安全的List 对象。
- static <K, V> Map<K, V> synchronizedMap(Map<K, V> m): 返回指定Map对象对应的线程安全的Map对象。
- static <T> Set<T> synchronizedSet(Set<T> s): 返回指定Set对象对应的线程安全的Set对象。
- static <K, V> SortedMap<K, V> synchronizedSortedMap(SortedMap<K, V> m): 返回指定SortedMap对象对应的线程安全的SortedMap对象。
- static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s): 返回指定SortedSet对象对应的线程安全的SortedSet对象。
7、线程池:
使用线程池的原因:1)构建新的线程是有代价的,因涉及与操作系统交互。2)减少并发线程的数目
如何获得线程池:执行器类Executor类中的newCachedThreadPool()等方法
步骤:1)获取线程池;2)调用submit提交Runnable或Callable对象;3)用完后调用shutdown。