线程主要涉及的内容以下几点
(以后有学习到新的再进行补充,新手描述嘤嘤嘤)
??首先需要分清线程和进程之间的区别,简单的来说在java中执行一个可执行程序,可以称它为进程。在启动main方法时,就启动了一个java.exe进程。在main方法中还可以产生额外的线程(程序执行的最小单位),这样就包括了main线程和其他线程。
1、继承Thread
public class MyThread extends Thread
{
//重写run方法
public void run()
{
//需要线程执行的代码
;
}
}
//start()为开始方法,只有执行了,线程才开始启动
new MyThread().start();
2、实现Runnable
public class MyThread implements Runnable
{
//重写run方法
public void run()
{
//需要线程执行的代码
;
}
}
new Thread(new MyThread()).start();
3、匿名类
new Thread()
{
public void run()
{
//需要线程执行的代码
;
}
}.start();
4、lambda表达式
//使用lambda表达式,只有在jdk8以后才可以用
new Thread(()->System.out.println("需要执行的代码")).start();
??最开始我接触这个概念是在操作系统中,学到所谓的PV操作,进行互斥和同步的操作。在数据库中也涉及到并发下操作数据的影响,三类错误、读锁,写锁都是当初的内容。总而言之,就是互斥和同步是并发下正常执行必须要掌握的。(这里不介绍基本概念啦!)
1、线程的同步
线程会执行指定的run()方法,那么怎样让它一直执行呢?
new Thread()
{
public void run()
{
//加上这个语句就会一直执行了
while(true)
{
//需要线程执行的代码
;
}
}
}.start();
当多个线程一起执行的话就叫并发,这样如果一起对一个数据一起修改的话就出现错误。这时就需要使用关键字synchronized
,使用synchronized
会让被修饰对象无法被多个线程同时操作。
//方式一
synchronized(对象名){
//需要执行的代码
}
//方式二 也可以放在方法前面
public synchronized void setName()
{
//对同一个实例对象,无法被多个线程同时执行
}
2、线程的互斥
如果想要一个线程在另一个线程之前执行,那么就需要互斥了。
//之前当前方法的线程会进行阻塞,并且释放对象锁(就是synchronized修饰的对象)
对象名.wait();
//如果需要唤醒就需要另外一个方法
对象名.notify()
对象名.notifyAll()
3、Thread的常用方法
//该线程休眠(暂停执行)1000毫秒=1s,如果有对象锁,也不会解开
Thread.sleep(1000);
//开始方法,不执行线程不会开始
Thread.start();
//使执行方法的对象线程加入到main线程中,执行完才继续mian线程
对象名.join()
//设置为守护线程
对象名.setDaemon(true);
//设置线程优先级
对象名.setPriority(Thread.MAX_PRIORITY);
??如果使用太多的线程,大量的启动和结束动作会导致系统的性能变卡,响应变慢。所以使用线程池思想,会使线程重复使用,不必重复启动。(下面复制了qaq)
//jdk自带线程池
ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
第一个参数10 表示这个线程池初始化了10个线程在里面工作
第二个参数15 表示如果10个线程不够用了,就会自动增加到最多15个线程
第三个参数60 结合第四个参数TimeUnit.SECONDS,表示经过60秒,多出来的线程还没有接到活儿,就会回收,最后保持池子里就10个
第四个参数TimeUnit.SECONDS 如上
第五个参数 new LinkedBlockingQueue() 用来放任务的集合
然后使用
execute方法用于添加新的任务
??Lock
和synchronized
类似,都可以达到同步和互斥,但是Lock
是程序实现,而后者语言自己实现。
1、使用
//Lock是个借口,需要找个类,这里使用 ReentrantLock
Lock lock = new ReentrantLock();
//然后在需要位置,执行以下方法
lock.lock();
//需要解锁时使用,通常在finally中实现,文档推荐
lock.unlock()
//只要使用一个lock对象就可以解决指定对象的同步问题
Condition condition = lock.newCondition();
condition.await();//对应wait()
condition.signal();//对应notify()
condition.signalAll();//对应notifyAll();
2、区别
(copy qaq)
Lock
是一个接口,而synchronized
是Java中的关键字
,synchronized是内置的语言实现,Lock是代码层面的实现。
Lock
可以选择性的获取锁(trylock
,解锁时需要判断是否有锁),如果一段时间获取不到,可以放弃。synchronized
不行,会一根筋一直获取下去。 借助Lock的这个特性,就能够规避死锁,synchronized
必须通过谨慎和良好的设计,才能减少死锁的发生。
synchronized
在发生异常和同步块结束的时候,会自动释放锁。而Lock
必须手动释放, 所以如果忘记了释放锁,一样会造成死锁。
3、对象锁
??对于一个萌新来说肯定疑惑过wait(),notify()这些方法一定要出现在对象锁之中吗?答案需要的,在百度之后发现,没有加synchronized
也没有什么问题,但是这样是没有意义的,而且很可能会发生死锁。所以Lock
就规定以一定要在lock()方法里面。
??原子操作就是不可拆分的操作,要么做,要么不做(就像是PV原语一样),如果分开操作,在并发下会造成数据的错误。
一、可用类
都在java.util.concurrent.atomic包,有用原子方法对int、int数组,boolean,long、long数组,对象引用,引用数组等进行操作方法
//jdk6以后
AtomicInteger atomicI =new AtomicInteger();
int i = atomicI.decrementAndGet();//减1
int j = atomicI.incrementAndGet();//加1
int k = atomicI.addAndGet(3);//与当前值相加,为负数是为减
本文为总结性文章,内容会有不足,请谅解。
原文:https://www.cnblogs.com/tddc10/p/12295481.html