1.进程和线程间的区别:
进程是执行着的应用程序,而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫做轻量级进程。
线程与进程的区别归纳:
a.地址空间和其它资源:进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
b.通信:进程间通信:管道、信号量、共享内存、消息队列(https://blog.youkuaiyun.com/zhaohong_bo/article/details/89552188 一些进程间通信的方法),线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
c.调度和切换:线程上下文切换比进程上下文切换要快得多。
d.在多线程OS中,进程不是一个可执行的实体。
2.多线程的好处以及问题:
(1)发挥多核 CPU 的优势
(2)更快的响应时间
(3)便于建模
问题:线程安全问题
3.多线程的优先级
线程优先级决定了线程能分配到的时间片的多少,也就决定了线程需要多或者少分配一些处理器资源,线程的优先级范围从1到10,在线程构建时可以通过setPriority(int)来修改优先级,默认优先级是5,设置优先级时,针对频繁阻塞(IO/休眠)的线程需要设置较高的优先级,而偏重计算(需要较多CPU时间或者偏运算)的线程则设置较低的优先级,确保处理器不会被独占。《Java并发编程的艺术》一书中,在Mac OS X10.10,jdk1.7环境下,设置优先级不起效,给出的原因是操作系统不理会java线程对于优先级的设定m,然而在Windos10,jdk 1.8环境下,亲测有效,可能是之后的版本对设置优先级进行了优化。但程序的正确性还是不要依靠线程优先级的高低比较好。下面是测试代码,有兴趣的同学可以尝试一下。
package art.ch4;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 测试线程优先级是否有效
*/
public class Priority {
private static volatile boolean notStart = true;
private static volatile boolean notEnd = true;
public static void main(String[] args) throws Exception {
List<Job> jobs = new ArrayList<Job>();
for (int i = 0; i < 10; i++) {
int priority = i < 5 ? Thread.MIN_PRIORITY : Thread.MAX_PRIORITY;
Job job = new Job(priority);
jobs.add(job);
Thread thread = new Thread(job, "Thread:" + i);
thread.setPriority(priority);
thread.start();
}
notStart = false;
Thread.currentThread().setPriority(8);
System.out.println("done.");
TimeUnit.SECONDS.sleep(10);
notEnd = false;
for (Job job : jobs) {
System.out.println("Job Priority : " + job.priority + ", Count : " + job.jobCount);
}
}
static class Job implements Runnable {
private int priority;
private long jobCount;
public Job(int priority) {
this.priority = priority;
}
public void run() {
while (notStart) {
Thread.yield();
}
while (notEnd) {
Thread.yield();
jobCount++;
}
}
}
}
4.守护线程(Deamon线程)
守护线程是一种支持型线程,主要用作程序中后台调度及支持性工作,当jvm中不存在非守护线程时,jvm将会退出,可以在线程启动前将其设置为守护线程,但不能在其启动后设置为守护线程。当没有非守护线程时,守护线程会立即结束,即使守护线程中又finally代码块,所以,蹦依靠守护线程中的finally中内容来关闭资源等。
5. 多线程共用一个数据变量注意什么
在Runnable中定义了全局变量,run方法回修改变量时,如果有多个线程同时使用该线程对象,那么就会造成全局变量的值被同时修改,造成错误。
ThreadLocal时jdk引入的一种机制,它用于解决线程间共享变量,使用ThreadLocal声明的变量,即使在线程中属于全局变量,针对每个线程来说,这个变量也是独立的。
volatile变量每次被线程访问时,都强迫线程从主内存中重读改变变量的最新值,而当该变量发生修改时,也会强迫线程将最新的值刷新回主内存中。这样,不同的线程都能及时的看到该变量的最新值。
6.线程间通信方式
线程孤立地运行,价值很小,但是多个线程相互能够互相配合,相互通信,会带来很大价值。
1.volatile关键字
关键字volatile可以用来修饰变量,就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的修改必须同部刷新回共享内存,这种特性能保证一个线程的修改,对其他线程可见。
2. 同步
同步是指多个线程通过 synchronized 关键字这种方式来实现线程间的通信。主要确保多个线程在同一时刻,只能有一个线程处于方法或者同步块中,保证了线程对变量访问的可见性和排他性。
3.wait/notify 机制
一个线程A调用了对象O的wait方法进入等待状态,而另一个对象B调用了对象O的notify或者notifyAll方法,线程A收到通知后从对象O的wait方法返回,进而执行后续操作。上述两个线程通过对象O来完成交互。
线程执行wait、notify、notifyAll都必须先获得锁。
4.管道输入/输出流
管道输入输出主要用于线程之间的数据传输,而传输的媒介位内存。,主要包括4种具体的实现:pipedOutputStream,pipedInputStream,pipedRead和pipedWriter,前两种面向字节,后两种面向字符。
5.join方法
线程A种执行了B.thread()方法,A等待B线程终止之后才从thread.join()方法返回,继续执行A线程。
参考:
1.https://www.nowcoder.com/ta/review-java/review?tpId=31&tqId=21079&query=&asc=true&order=&page=11
2.《java并发编程的艺术》