java线程技术分享,java多线程技术点( 二 )


  • 互斥条件:顾名思义,线程对资源的访问是排他性,当该线程释放资源后下一线程才可进行占用 。
  • 请求和保持:简单来说就是自己拿的不放手又等待新的资源到手 。线程T1至少已经保持了一个资源R1占用,但又提出对另一个资源R2请求,而此时,资源R2被其他线程T2占用,于是该线程T1也必须等待,但又对自己保持的资源R1不释放 。
  • 不可剥夺:在没有使用完资源时 , 其他线性不能进行剥夺 。
  • 循环等待:一直等待对方线程释放资源 。
我们可以根据死锁的四个必要条件破坏死锁的形成 。
1.6 补充:并发和并行的区别
并发:是指在某个时间段内,多任务交替的执行任务 。当有多个线程在操作时 , 把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行 。在一个时间段的线程代码运行时,其它线程处于挂起状 。
并行:是指同一时刻同时处理多任务的能力 。当有多个线程在操作时,CPU同时处理这些线程请求的能力 。
区别就在于CPU是否能同时处理所有任务,并发不能 , 并行能 。
1.7 补充:线程安全三要素
  • 原子性:Atomic包、CAS算法、Synchronized、Lock 。
  • 可见性:Synchronized、Volatile(不能保证原子性) 。
  • 有序性:Happens-before规则 。
1.8 补充:如何实现线程安全
  • 互斥同步:Synchronized、Lock 。
  • 非阻塞同步:CAS 。
  • 无需同步的方案:如果一个方法本来就不涉及共享数据,那它自然就无需任何同步操作去保证正确性 。
1.9 补充:保证线程安全的机制:
  • Synchronized关键字
  • Lock
  • CAS、原子变量
  • ThreadLocl:简单来说就是让每个线程,对同一个变量,都有自己的独有副本,每个线程实际访问的对象都是自己的,自然也就不存在线程安全问题了 。
  • Volatile
  • CopyOnWrite写时复制
随着CPU核心的增多以及互联网迅速发展,单线程的程序处理速度越来越跟不上发展速度和大数据量的增长速度,多线程应运而生,充分利用CPU资源的同时,极大提高了程序处理速度 。
java线程技术分享,java多线程技术点

文章插图
创建线程的方法
继承Thread类:
public class ThreadCreateTest {
public static void main(String[] args) {
new MyThread.start;
}
}
class MyThread extends Thread {
@Override
public void run {
System.out.println(Thread.currentThread.getName + "\t" + Thread.currentThread.getId);
}
}
实现Runable接口:
public class RunableCreateTest {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable;
new Thread(runnable).start;
}
}
class MyRunnable implements Runnable {
@Override
public void run {
System.out.println(Thread.currentThread.getName + "\t" + Thread.currentThread.getId);
}
}
通过Callable和Future创建线程:
public class CallableCreateTest {
public static void main(String[] args) throws Exception {
// 将Callable包装成FutureTask,FutureTask也是一种Runnable
MyCallable callable = new MyCallable;
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start;
// get方法会阻塞调用的线程
Integer sum = futureTask.get;
System.out.println(Thread.currentThread.getName + Thread.currentThread.getId + "=" + sum);
}
}
class MyCallable implements Callable<Integer> {
@Override
public Integer call throws Exception {
System.out.println(Thread.currentThread.getName + "\t" + Thread.currentThread.getId + "\t" + new Date + " \tstarting...");
int sum = 0;
for (int i = 0; i <= 100000; i++) {
sum += i;
}
Thread.sleep(5000);
System.out.println(Thread.currentThread.getName + "\t" + Thread.currentThread.getId + "\t" + new Date + " \tover...");
return sum;
}
}
线程池方式创建:
实现Runnable接口这种方式更受欢迎,因为这不需要继承Thread类 。在应用设计中已经继承了别的对象的情况下 , 这需要多继承(而Java不支持多继承,但可以多实现?。? ,只能实现接口 。同时,线程池也是非常高效的,很容易实现和使用 。
实际开发中 , 阿里巴巴开发插件一直提倡使用线程池创建线程,原因在下方会解释,所以上面的代码我就只简写了一些Demo 。
2.1 线程池创建线程
线程池,顾名思义,线程存放的地方 。和数据库连接池一样,存在的目的就是为了较少系统开销 , 主要由以下几个特点:


推荐阅读