1.线程的四种创建方式:
1.直接继承Thread的方式去实现线程的创建:
/**
* 创建线程方式一:
*/
public class test01 {
public static void main(String[] args) {
ThreadDemo01 threadDemo01 = new ThreadDemo01();
threadDemo01.start();
}
}
class ThreadDemo01 extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
1.1通过内部类直接创建,效果和上面是一样的。
//通过内部类直接创建:
public class test02 {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
thread.start();
}
}
底层代码分析:
/* What will be run. */
private Runnable target;
-----------------------------------------
@Override
public void run() {
if (target != null) {
target.run();//在这里,底层给我们写好了,可以直接调用run方法。
}
}
----------------------------------------------
//直接去实现Runnable接口
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
2.通过实现Runable
//实现Runnable接口
public class testRunable {
public static void main(String[] args) {
new Thread(new TestRunnableDemo(),"Runnable").start();
}
}
class TestRunnableDemo implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
从底层来看,一个类去继承Thread和去实现Runnable的本质是一样的,最终的结果都是调用Runnable接口的run方法。
3.实现Callable接口:
public class TestCallable {
public static void main(String[] args) {
//1.创建对应的对象
TestCallableDemo testCallableDemo = new TestCallableDemo();
//2.需要通过FutureTask的实现类的支持,并用于接收运行结果
FutureTask<String> futureTask = new FutureTask<>(testCallableDemo);
//3.开启线程
new Thread(futureTask).start();
//4.接收运行的结果:
try {
String s = futureTask.get();
System.out.println("这个是获取到的值为:"+s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class TestCallableDemo implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName());
return "Callable";
}
}
- Java 5.0 在java.util.concurrent提供了一个新的创建执行线程的方式:Callable接口。
- Callable接口类似于Runnable,两者都是为那些实例可能被另一个线程执行的类设计的,但是Runnable不会返回结果,并且无法抛出经过检查的异常,但是Callable是可以有返回结果,并且可以抛出检查的异常的。
- Callable需要依赖FutureTask,FutureTask也可以用作闭锁。
1) FutureTask(实现类)实现了RunnableFuture(接口)。
2)RunnableFuture继承了Runnable(接口)和Future(接口)。
4.利用线程池实现:
public class TestThreadPool {
public static void main(String[] args) {
TestThreadPoolDemo testThreadPoolDemo = new TestThreadPoolDemo();
//1.通过Executors.newFixedThreadPool
ExecutorService pool = Executors.newFixedThreadPool(5);
//2.为线程中的线程分配任务
pool.submit(testThreadPoolDemo);
//3.关闭线程池:
pool.shutdown();
}
}
class TestThreadPoolDemo implements Runnable{
private int i=0;
@Override
public void run() {
while(i<=100){
System.out.println(Thread.currentThread().getName()+" : "+ i++);
}
}
}
4.1通过内部类直接实现:
public class TestThreadPool {
public static void main(String[] args) {
//1.创建线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
//2.通过内部类完成对值的传递
Future future = pool.submit(new Callable<Integer>() {
int sum = 0;
@Override
public Integer call() throws Exception {
for (int i = 0; i <=100 ; i++) {
sum+=i;
}
return sum;
}
});
//3.取值
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//4.关闭线程池
pool.shutdown();
}
}
一、线程池:提供了一个线程队列,队列中保存这所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。
二、线程池的体系结构:
java.util.concurrent.Exector:负责线程的使用与调度的根接口
java.util.concurrent.Executor : 负责线程的使用与调度的根接口
|–**ExecutorService 子接口: 线程池的主要接口
|–ThreadPoolExecutor 线程池的实现类
|–ScheduledExecutorService 子接口:负责线程的调度
|–ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService
三、工具类:Executors
ExecutorService ==》 newFixedThreadPool() : 创建固定大小的线程池
ExecutorService ==》 newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
ExecutorService ==》 newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程
ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。
2. JUC简介:
在Java 5.0 提供了java.util.concurrent(简称JUC)包,在此包中添加了再并发编程中很常用的使用工具,用于定义类似于线程的自定义子系统,包括线程池,异步IO和轻量级任务框架。提供可调的、灵活的线程池。还提供了设计用于多线程上下文的Collection实现等。
3. volatile关键字 内存可见性
- 内存可见性(Memory Visibility)是值当前某个线程正在使用对象状态而另一个线程正在修改该状态,需要确保当一个线程修改了对象状态后,其他线程能够看到发生的状态变化。
- 可见性错误是指当前读操作与写操作在不用的线程中执行时,我们无法确保执行读操作的线程能实时地其他线程写入的值,有是甚至是根本不可能做的事情。
- 我们可以通过同步来保证对象被安全的发布。除此之外,我们也可以使用一种更加轻量级的volatile变量。
- Java提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程,可以将volatile看做一个轻量级的锁,但是又与锁有些不同:
- 对于多线程,不是一种互斥关系
- 不能保证变量状态的“原子性操作”
- volatile相对于synchronized是一种较为轻量级的同步策略。
//volatile不具备互斥性。
//volatile不能保证变量的原子性
public class TestVolatile {
public static void main(String[] args) {
TestVolatileDemo testVolatileDemo = new TestVolatileDemo();
new Thread(testVolatileDemo).start();
while(true){
if (testVolatileDemo.isFlag()){
System.out.println("----------------");
break;
}
}
}
}
class TestVolatileDemo implements Runnable{
private volatile boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag="+isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
4. CAS算法
模拟CAS算法:
public class TestCompareAndSwap {
public static void main(String[] args) {
final CompareAndSwap cas=new CompareAndSwap();
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int expectedValue = cas.get();
boolean b = cas.compareAndSet(expectedValue,(int)(Math.random()+101));
System.out.println(b);
}
}).start();
}
}
}
class CompareAndSwap{
private int value;
//获取内存值
public synchronized int get() {
return value;
}
//比较
public synchronized int compareAndSwap(int ecpectedValue,int newValue) {
int oldValue=value;
if(oldValue == ecpectedValue) {
this.value = newValue;
}
return oldValue;
}
public synchronized boolean compareAndSet(int expectedValue, int newValue) {
return expectedValue == compareAndSwap(expectedValue, newValue);
}
}
- CAS(Compare-And-Swap)是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问。
- CAS是一种无所的非阻塞算法的实现。
- CAS包含了三个操作数:
- 需要读写的内存值V
- 进行比较的值A
- 拟写入的新值B
- 当且仅当V的值等于A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作。
原子性:
/*
* 一、i++的原子性问题:实际上是分为三个步骤,读-该-写
* 二、解决方案:原子变量:jdk1.5后java.util.concurrent.atomic包下提供了常用的原子变量
* 1.volatile 保证内存可见性。
* 2.CAS(Compare-and-swap)算法保证数据的原子性。
* CSA算法是硬件对于并发操作共享数据的支持。
* CSA包含了三个操作:内存值 V 预估值A更新值B;当且仅当V==A时,V=B,否则不做任何操作
*/
public class TestAtomicDemo {
public static void main(String[] args) {
AtomicDemo ad = new AtomicDemo();
for (int i = 0; i < 10; i++) {
new Thread(ad).start();
}
}
}
class AtomicDemo implements Runnable{
//private volatile int serialNumber=0;
private AtomicInteger serialNumber=new AtomicInteger();
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()+"="+getSerialNumber());
}
public int getSerialNumber() {
return serialNumber.getAndIncrement();
}
}
5. ConcurrentHashMap锁分段机制:
Java 5.0 在java.util.concurrent包中提供了多种并发容器类来改进同步容器的性能。
ConcurrentHashMap同步容器类是Java 5增加的一个线程安全的哈希表。对于多线程的操作,介于HashMap与HashTable之间,内部采用“锁分段”机制代替HashTable的独占锁。进而提高性能。
此包还提供了设计用于多线程上下文中的Collection实现:
ConcurrentHashMap、COncurrentSkipListMap、COncurrentSkipListSet、CopyOnWriteArrayList和CopyOnWriteArraySet。当期望许多线程访问一个给定collection时,ConcurrentHashMap通常由于同步线程的HashMap,ConcurrentSkipListMap通常优于同步的TreeMap。当企鹅昂的读书和遍历远远大于列表的更新数时,CopyOnWriteArrayList由于同步的ArrayList。
如果同一组数据,即读取,有写入的话,这样是会报错的。
/**
* 直接使用会报错:private static List<String> list = Collections.synchronizedList(new ArrayList());
* ConcurrentModificationException
* 因为操作的是同一组数据。
*
* CopyOnWriteArrayList/CopyOnWriteArraySet:"写入并复制"
* 注意:
* 添加操作多时,效率低,因为每次添加时都会进行复制,开销非常大。并发迭代操作多时,可以选择。
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class TestCopyOnWriteArrayList {
public static void main(String[] args) {
HelloThread hThread = new HelloThread();
for (int i = 0; i < 10; i++) {
new Thread(hThread).start();
}
}
}
class HelloThread implements Runnable{
//private static List<String> list = Collections.synchronizedList(new ArrayList());
private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList();
static {
list.add("AA");
list.add("BB");
list.add("CC");
}
@Override
public void run() {
// TODO Auto-generated method stub
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
list.add("123");
}
}
}