Java并发编程-多线程

摘要:
自JDK1.5以来,Java提供了Executor框架来创建不同的线程池。有关线程池使用的更多信息,请参阅:Java线程池ThreadPoolExecutor&&Executors6、CyclicBarrier、CountDownLatchCyclicBarrar和CountDownLatch都具有用于多个线程之间协作的计数函数。相关函数:Java锁、关键字volatile 8和ThreadLocalThreadLocal通常称为线程本地变量。它们将变量绑定到线程,为每个线程维护一个独立的变量副本,并维护同一线程中对象的可见范围。

1、进程与线程

  一个程序就是一个进程,一个程序中的多个任务被称为线程。进程是资源分配的基本单位,线程是进程中执行运算的最小单位,亦是调度运行的基本单位。多线程的好处并发执行提高了程序的效率,CPU不会因为某个线程需要等待资源而进入空闲状态

2、线程的实现方式

  • 继承java.lang.Thread类
  • 实现java.lang.Runnable接口,然后交给java.lang.Thread类执行
  • 实现java.util.concurrent.Callable接口,作为参数构建一个java.util.concurrent.FutureTask对象,然后交给java.lang.Thread执行。
  • 使用java.util.concurrent.Executors类的线程池
public class ThreadTest {
    public void test1() {
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "这是一个返回值";
            }
        };
        FutureTask<String> futureTask = new FutureTask<String>(callable);
        new Thread(futureTask).start();
        try {
            System.out.println(futureTask.get()); // get方法会阻塞主线程的执行
        } catch (Exception e) {
        }
        System.out.println("执行完毕");
    }
}

3、wait()、notify()/notifyAll()、sleep()

  wait()、notify()/notifyAll()方法是Object对象中的方法,他们必须结合synchronized关键字使用,主要用于线程间的通讯。wait()会交出对象的控制权,然后让线程处于等待状态;notify()会唤醒一个等待这个对象控制权的线程(如果有多个线程,唤醒哪个线程由操作系统决定),等待线程在获取对象控制权后会继续执行(注意:调用notify时不会释放对象的控制权,必须运行到synchronized块结束);notifyAll()会唤醒所有等待线程。

  sleep()是Thead类中的静态方法,用户将线程暂停一段时间,时候到后程序继续执行,不涉及到线程通讯和对象锁。

4、interrupt()、interrupted()、isInterrupted()

  这3个方法都是Thread类中的方法。

  interrupt用于中断线程,如果需要中断的线程不是interrupt()调用者线程,系统会检查权限,只有权限允许的情况下才会中断,否则会报错。中断线程仅仅是指设置一下中断状态标记,并不会停止线程。当线程处于wait、sleep、join阻塞状态时,中断线程会打破这种阻塞,并让这些方法抛出InterruptedException异常,并且中断标志状态还原。

  interrupted是一个静态方法,用于判断当前线程是否处于中断状态,调用后会清除中断标志。

  isInterrupted()用于判断线程是否处于中断状态,它不会清除中断标志。

  实际中这几个用到不多,感觉就是为了解除死锁用的。

5、线程池

  线程的创建要花费昂贵的资源和时间,如果任务来了才创建创建线程那么响应时间会边长,而且一个进程能创建的线程有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们就被称为线程池。从JDK1.5起,Java提供了Executor框架来创建不同的线程池。

  更多关于线程池的使用查看:Java线程池ThreadPoolExecutor&&Executors

6、CyclicBarrier和CountDownLatch

  CyclicBarrier和CountDownLatch都具有计数功能,用于多线程间的协作。

  详细参考:Java并发编程-CountDownLatch&CyclicBarrier

7、线程安全

  提到线程安全,我们就必须了解一下并发编程的三个问题:

  • 原子性:即一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。代码 i++、j=i、k=i+j等就不具备原子性,i++有取值、运算、赋值3个操作指令
  • 可见性:可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值
  • 有序性:程序执行的顺序按照代码的先后顺序执行,CPU有时会优化指令排序,所以代码的执行运行不一定是我们代码的书写顺序。

  在并发编程中,只有上面出现其中任何一个问题都可能会导致程序运行不正确。

  相关功能:Java锁关键字volatile

8、ThreadLocal

  ThreadLocal一般称为线程本地变量,它将变量与线程绑定在一起,为每个线程维护一个独立的变量副本,并且将对象的可见范围维护在同一个线程内。线程变量会存储在ThreadLocalMap对象中(看着是个map,事实它内部只有数组,没有链表,但也有相似特征,数组初始化容量都为16,都是双倍扩展),它是Thread的内部变量,初始为空。

  应用中我们会定义多个ThreadLocal对象,ThreadLocal在初始化时就确定了threadLocalHashCode(通过AtomicInteger增长实现),也就是确定了ThreadLocalMap内部数组中的位置。

  在Web应用系统中,我们常通过拦截器将用户登录信息存储在ThreadLocal中,这样我们就可以随时随地获取到登录用户信息。

9、线程通讯

  • 共享变量
  • wait, notify,notifyAll(这3个方法是Object对象中的方法,且必须与synchronized关键字结合使用)
  • CyclicBarrier、CountDownLatch
  • Lock/Condition机制
  • 管道,创建管道输出流PipedOutputStream和管道输入流PipedInputStream
  • 利用LockSupport

  详细代码示例见:Java并发编程-线程间通讯

免责声明:文章转载自《Java并发编程-多线程》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇深入探究Lua的GC算法(下)-《Lua设计与实现》测试人员的KPI考核制定下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

《是时候淘汰对操作系统的 fork() 调用了

是时候淘汰对操作系统的 fork() 调用了 - InfoQ 概述 一般观点认为针对线程创建 Unix 的 fork() 与 exec() 的组合堪称绝配,但微软研究院与波士顿大学联合发表的一篇论文则提出了相反的观点。他们认为 fork 在当下早已过时,对操作系统和应用程序的设计弊大于利,并给出了一些替代 fork 的方案和未来的发展路线建议。 1 引言...

Oracle Parallel 多线程

对于一个大的任务,一般的做法是利用一个进程,串行的执行,如果系统资源足够,可以采用parallel技术,把一个大的任务分成若干个小的任务,同时启用n个进程/线程,并行的处理这些小的任务,这些并发的进程称为并行执行服务器(parallel executeionserver),这些并发进程由一个称为并发协调进程的进程来管理。 启用Parallel前的忠告:只有...

线程及视频解码过程6-16

线程 一、为了让音视频更好的解码,这里我们需要采用多线程,用一个线程解码视频,一个线程解码音频,我们需要: 1.调用线程库 #include <thread> 2.std:thread t1(); 创建相应线程。 3、为了让每个线程更好的区分资源属于哪一个线程,我们可以用类来实现线程,在对应得类中用成员来区分。 例如:      通过新建一个...

C++面试

https://blog.csdn.net/weixin_44363885/article/details/99567746 这一行是个 贼鸡巴重要的链接!!!   很好的总结 我直接复制到下面了: 社招:社招的同学,无论是1-3年经验,还是中途转行,都可参考。写简历必须有针对性,以后台开发为例,请去拉勾网 / 猎聘 / 智联招聘等网站,多看看后台开发的J...

MySQL MySql连接数与线程池

MySql连接数与线程池 by:授客 QQ:1033553122   连接数1、  查看允许的最大并发连接数 SHOW VARIABLES LIKE 'max_connections';   2、  修改最大连接数 方法1:临时生效 SET GLOBAL max_connections=200; SET语法参考: http://dev.my...

Linux-pthread如何设置线程的优先级

设置线程优先级的函数: int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param) 它主要用于设置线程的调用策略和优先级。 参数说明: 1.  target_thread是使用pthread_create所获得的线程ID。  ...