创建线程
1.继承Thread
public class Main {
public static void main(String[] args) throws ParseException {
MyThread t=new MyThread();
t.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":hello");
}
}
2.实现Runnable接口
public class Main {
public static void main(String[] args) throws ParseException {
Thread t=new Thread(new MyThread());
t.start();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":hello");
}
}
3.线程池
Executor:线程池顶级接口
ExecutorService:线程池接口,可通过submit(Runnable task)提交任务代码
Executors工厂类:通过此类可以获得一个线程池
方法:
newFixedThreadPool(int nThreads)获取固定数量的线程池
newCachedThreadPool()获得动态数量的线程池
public class Main {
public static void main(String[] args) throws ParseException {
ExecutorService es=Executors.newFixedThreadPool(2);
es.submit(MyThread.getMyThread());
es.submit(MyThread.getMyThread());
es.shutdown();
}
}
class MyThread implements Runnable{
public static int res=0;
public static int index=1;
public static MyThread m=new MyThread();
private MyThread(){ }
public static MyThread getMyThread(){
return m;
}
Lock lock=new ReentrantLock();
@Override
public void run() {
while(index<=10000){
try {
lock.lock();
if(index>10000){
break;
}
res += index;
index++;
System.out.println(Thread.currentThread().getName() + " " + res);
}finally {
lock.unlock();
}
}
}
}
Callable接口
JDK1.5加入,与Runnable接口相似,实现之后代表一个线程任务
Callable具有泛型返回值,可以声明异常
public interface Callable{
public V call() throws Exception;
}
返回值通过Future接口接收
get()阻塞形式等待Future中的异步处理结果(call()的返回值)
public static void main(String[] args) throws ParseException {
ExecutorService es=Executors.newFixedThreadPool(2);
//用Future接收
Future<String> future=es.submit(new MyCallable());
try {
//future.get()方法得到返回值
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
es.shutdown();
}
}
class MyCallable implements Callable<String>{
@Override
public String call() throws Exception {
return "hello";
}
}
Thread类常见方法
Thread.sleep(毫秒)
让当前进程进入休眠,让出CPU使用权,直到休眠结束才会继续抢占CPU 不会释放锁
Thread.yield()
线程礼让 让出CPU使用权 但是会马上又去抢占CPU,进入就绪态,不会释放锁
join()
在当前线程中加入另一线程,必须将另一线程执行完后才会继续执行当前线程
加锁方式
Synchronized
可以加在代码块和方法上
方式一:同步代码块
- synchronized(临界资源对象){ //互斥锁标记
- //原子代码
- }
方式二:同步方法
- public synchronized void sale(){ //互斥锁标记是this对象
- //原子代码
- }
Lock
class MyThread implements Runnable{
public static int res=0;
public static int index=1;
public static MyThread m=new MyThread();
private MyThread(){ }
public static MyThread getMyThread(){
return m;
}
Lock lock=new ReentrantLock();
@Override
public void run() {
while(index<=10000){
try {
lock.lock();
if(index>10000){
break;
}
res += index;
index++;
System.out.println(Thread.currentThread().getName() + " " + res);
}finally {
lock.unlock();
}
}
}
}
lock锁一定要采用以下形式:
Lock l = …;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
不然如果前面代码出现异常执行不下去导致没有unlock 会导致死锁(unlock必须执行)
读写锁
ReetrantReadWriteLock:
1.创建读写锁对象:ReadWriteLock rwl = new ReentrantReadWriteLock();
2.创建读锁 :Lock readLock = rwl.readLock();
3.创建写锁:Lock writeLock = rwl.writeLock();
class RandW{
private static RandW rw=new RandW();
ReadWriteLock rwlock=new ReentrantReadWriteLock();
Lock readlock=rwlock.readLock();
Lock writelock=rwlock.writeLock();
private RandW(){}
public static RandW getRandW(){
return rw;
}
String msg;
public void setMsg(String msg){
try{
writelock.lock();
this.msg=msg;
}finally {
writelock.unlock();
}
}
public void getMsg(){
try {
readlock.lock();
System.out.println(msg);
}finally {
readlock.unlock();
}
}
}
class MyThread3 implements Runnable{
@Override
public void run() {
RandW rw=RandW.getRandW();
rw.setMsg("hello");
}
}
class MyThread4 implements Runnable{
@Override
public void run() {
RandW rw=RandW.getRandW();
rw.getMsg();
}
}
MyThread3读 MyThread4写
重入锁
重入锁:
-
重入锁也叫作递归锁,指的是同一个线程外层函数获取到一把锁后,内层函数同样具有这把锁的控制权限
-
synchronized和Lock锁都可以实现锁的重入
公平锁
公平锁和非公平锁
- 非公平锁:优先使用上一个线程接着执行下面的线程任务
- synchronized是非公平锁的实现,无法实现公平锁
- lock锁默认是非公平锁,如果想要实现公平锁,那么需要在构造方法设置为true
- 公平锁:让每个线程都公平去执行线程任务
- lock锁可以实现公平锁
- synchronized无法实现公平锁
//Lock锁实现公平锁 参数为true表示是公平锁,默认是false表示非公平锁
Lock lock = new ReentrantLock(true);
synchronized锁升级
锁的状态总共有四种
- 无锁
- 当锁对象被创建,还没有线程进入的是,此时锁对象处于无锁状态
- 偏向锁
- 当有线程A进入同步代码并获得锁对象,此时会保存线程ID。以后此线程A进入到同步代码中则无需使用CAS加锁或者释放锁。只需要验证线程ID即可。
- 轻量级锁(自旋锁)
- 当前锁处于偏向锁,此时后线程B进入到同步代码。这是线程AB会使用CAS竞争,并升级为轻量级锁
- 重量级锁
- 如果线程没有获得轻量级锁,线程会通过CAS自旋获取锁对象,如果自旋次数大于阈值(10次),则升级为重量级锁。
- 如果线程没有获得轻量级锁,线程会通过CAS自旋获取锁对象,如果自旋次数大于阈值(10次),则升级为重量级锁。