Java并发编程

并发编程中的3个概念
1.原子性:操作中包含的步骤,要么都执行成功,要么都失败。
2.可见性:一个线程修改了变量的值,其他线程能够立即看到修改的值。
3.有序性:JVM处理器在执行指令时会重排序以优化运行效率,但是会考虑数据依赖问题。但是如果多线程时重排序会造成程序执行的正确性。所以多线程时要保证代码执行的有序性。

原子性

例如:
x = 10; //语句1
y = x; //语句2
x++; //语句3
x = x + 1; //语句4
上面4个语句,哪些是原子性操作?
答:第一个是,其他的都不是。第一个x赋值为10,然后再同步到主存中,是一个原子操作。
第二个首先要从主存中读x的值,然后再赋值给y,2个步骤各自是原子操作,但合在一起不是原子操作。
同理x++,x=x+1,也不是原子操作。

可以看出Java内存模型中读取、赋值操作为原子操作。那如何保证更大范围的原子操作呢?
那就使用到了synchronized和Lock,这两个悲观锁可以保证同一时刻只有一个线程访问被修饰的代码,自然也就是原子操作了。

可见性

经过volatile修饰的共享变量,可以将修改后的值立即更新到主存。如果普通共享变量,值更新到主存的时机是不确定的,所以没有可见性。除此之外,synchronized和Lock在释放锁之前会更新主存,也能保证可见性。

有序性

Java内存模型允许编译器、处理器对指令重排序,单线程无影响,多线程会影响,所以synchronized、Lock都能保证有序性。
添加volatile关键字修饰后,能够保证一定的有序性,同时Java内存模型先天有一些happens-before原则也可以保证有序性。
happens-before(先行发生行为)原则:
程序次序规则:一个线程内,按照书写顺序,写在前面的先执行。事实上单线程程序指令依然会重排,但是能够保证结果的一致性。
锁定规则:一个锁必须释放后,才能够继续加锁。
volatile规则:写操作发生在读操作之前。一个线程写,一个线程读,读在写后面。
传递规则:A操作先于B操作,B操作先于C操作,则A操作限于C操作。
线程启动规则:Thread的start()方法先行于线程内的一切操作。
线程中断规则:Thread的interrupt()方法先行于该线程代码检测到中断事件的发生。
线程的终结规则:线程中所有的操作都先行于线程的终止检测。
对象的终结规则:一个对象的初始化方法先行于finalize()方法的开始。

相关题目

1.进程和线程之间区别?
一个进程是一个独立的运行环境,线程是进程中的一个任务,进程中可以包含多个线程,各个线程间可以共享进程的资源。
2.多线程编程的好处?
多线程用以提高程序的执行效率,一些线程资源等待时,cpu可以去处理其他线程,减少了空闲状态。多个线程间还可以共享堆内存,所以多线程程序比单线程程序更好。
3.用户线程和守护线程的区别?
默认新建的thread是用户线程,thread.setDaemon(true)可设置守护线程。平常处理逻辑的线程为用户线程,程序运行时在后台提供通用服务的线程设置为守护进程(如jvm的垃圾回收线程)。守护线程创建的线程也是守护线程。
4.如何创建线程?
两种方法:通过继承Thread类或者实现Runable接口覆盖或实现其中的run()方法,然后再调用new thread再start()
5.线程的生命周期?
新建:当new thread()时,线程处理“新建”状态;
就绪&运行:thread.start()之后,如何没有分配cpu等资源为就绪,分配了cpu等资源为运行状态;
阻塞:线程被挂起为阻塞状态,如thread.join(),thread.sleep(),等待用户输入等,将线程放入到阻塞队列中,阻塞消除变为就绪状态;
等待:当前线程需要等待其他线程的一些特定动作时(如某个对象被synchronized(o)加锁;o.wait()时需要其他线程o.notify()、o.notifyAll()唤醒);
超时等待:等待的基础上,超时了;
终止:线程运行完毕。

image.png

6.我们可以直接调用thread的run()方法吗?
可以的,直接调用和普通类就一样了。如果要在一个线程中启动另一个线程的话,就需要thread.start()了
7.线程的优先级?
我们可以定义线程的优先级,1代表最低,10代表最高,一般来说高优先级线程会有具有优先权,但是它的实现是操作系统实现的,并不能一定保证高优先级在低优先级线程前执行。
8.什么是线程调度器Thread Schedule和时间分片time slicing?
线程调度器是一个操作系统服务,它负责为就绪态的线程分配CPU时间片,可以继续线程优先级或线程等待时间,尽量通过程序自己控制线程的调度,而不是依赖于不同操作系统的默认实现。
9.什么是多线程中的上下文切换(context-switching)?
上下文切换时存储和恢复CPU状态的过程,它使得线程能够从中断点恢复执行。
10.如何确保main()方法是程序最终结束的线程?
在main()方法中开启别的线程时,使用别的线程对象.join()方法,将其同步在main()线程里即可。
11.线程间如何通信?
线程间如果共享资源时,可以采用object对象的wait(),notify(),notiyAll()等方法通过加锁的方式进行通信。
12.为什么Java中wait(),notify()t,notifyAll()方法被定义在Object类里?
因为Java并没有可供所有对象使用的锁、同步器,但是所有类都继承Object类,这样每个对象都拥有了锁、监视器可用。
13.为什么wait(),notify(),notifyAll()方法必须要在同步方法或者同步代码块中被调用?
因为对象的这些方法要调用的话,该线程必须持有该对象的锁,调用完方法后再释放锁以便让其他线程可以得到这个锁继续操作,这样就需要通过同步来实现。
14.为什么thread的sleep和yield方法是静态的?
这是一个调用对象的强制规范问题,因为sleep和yield只能对运行中的线程起作用,使用静态让这两个方法只能强行获取当前线程对象并操作,如果不指定静态那么可以控制其他非运行状态的线程执行该方法,显然是不可以的。
15.如何确保线程安全?
这里线程安全指的是线程间共享资源时不会错乱。
1:通过synchronized来对对象加锁实现线程安全;
2:使用线程安全的集合如ConcurrentHashMap来存储共享数据;
3:使用原子类如AtomicInteger存储共享数据;
4:使用锁;
5:使用volatile关键字修饰变量,保证线程从堆内存读取数据,而不是从线程cache读取数据。
16.volatile关键字的作用?
volatile关键字用来修饰变量,被修饰的变量具有多线程下的可见性、有序性、原子性(保证原子操作,原子操作的组合操作不能保证原子性)
17.同步块和同步方法哪个更好?
同步块往往对对象的锁能精确到更细粒度,所以使用同步块较好。
18.如何创建守护线程?
新建一个thread后,thread.setDaemon(true)然后再调用thread.start()就可以了。
19.什么是ThreadLocal?
线程类中的普通全局变量,在多线程的时候会有线程不安全的问题,可以使用TheadLocal变量,各个线程通过get()、set()方法获得各自线程的变量。
20.什么是Thread Group,为什么不建议使用它?
ThreadGroup这个类提供了关于线程组的信息,主要2个功能是获取线程组中活跃线程列表、为线程设置线程外部异常处理(因为线程run()方法不能抛出异常,只能打日志)。Java1.5后可以通过setUncaughtExceptionHandler(UncaughtExceptionHandler eh) 来设置,ThreadGroup已经过时,所以不建议使用。
21.什么是Thread Dump线程转储?
是一个JVM活动线程的列表,可以用来分析系统瓶颈死锁等,一般使用JDK自带的jstack等工具来分析。
22.什么是死锁DeadLock,如何分析和避免死锁?
两个以上的线程永远互相阻塞的情况叫做死锁。
分析死锁:通过分析Thread Dump查看阻塞的线程以及他们等待的资源,每个资源有id,可以根据资源的id查看哪些线程拥有了它的对象锁。
避免死锁:避免嵌套锁,在需要的地方使用,避免无期限等待。
23.什么是Java Timer类?
Java Timer类是一个工具类,可以安排一个线程在未来的某个时间点执行,执行一次或者周期执行。TimerTask是一个实现了Runnable接口的抽象类,继承它然后交给Timer对象安排即可。


package com.journaldev.threads;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class MyTimerTask extends TimerTask {

    @Override
    public void run() {
        System.out.println("Timer task started at:"+new Date());
        completeTask();
        System.out.println("Timer task finished at:"+new Date());
    }

    private void completeTask() {
        try {
            //assuming it takes 20 secs to complete the task
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String args[]){
        TimerTask timerTask = new MyTimerTask();
        //running timer task as daemon thread
        Timer timer = new Timer(true);
        timer.scheduleAtFixedRate(timerTask, 0, 10*1000);
        System.out.println("TimerTask started");
        //cancel after sometime
        try {
            Thread.sleep(120000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        timer.cancel();
        System.out.println("TimerTask cancelled");
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

24.什么是线程池?
线程池用于管理多个工作线程。Executors是线程池的工厂类可以方便的创建线程池对象。

1. newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

25.
26.
27.
28.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352