--什么是进程什么线程:
- 进程:操作系统分配资源和调度的基本单位
- 线程:进程中的一个执行单元,CPU调度的基本单元
所以一个进程可以包含多个线程,这些线程共享进程的内存空间和资源
--进程与线程的区别:
- 资源分配上:进程与进程之间相互独立,每个进程拥有自己独立的内存空间和系统资源
线程共享自己对应进程的资源 - 切换开销上:线程的切换开销小于进程(线程共享进程资源,所有线程间切换不用更换内存地址空间)
- 通信方式上:进程之间的通信 需要通过 进程间通信机制,如管道、消息队列、共享内存等
而 线程之间通信 直接通过共享内存就可以
CPU 核心处理器:
-
单核心单线程CPU: 执行运行单线程程序 ,如果需要执行多个线程 只能在CPU上交替执行 不会有性能的提升
-
多核心多线程CPU: CPU的线程数量越多 ,执行多线程程序的效率就越高 上限越高 ,但是最大效率受到CPU线程数的限制
--什么是程序(分为两种状态)
-
非运行:代码文件 + 资源文件
-
运行:程序被操作系统加载到内存中运行时,称为进程,此时程序处于动态执行状态
-
通过(代码-计算机硬件设备指令集)调用计算机资源(CPU+RAM+IO)解决问题
-
--Java实现线程的方式
- 继承Tread类
(run方法也是被重写了,但是不重写run方法不报错)
class ThreadDemo extends Thread { String ID; public ThreadDemo(String ID) { this.ID = ID; } public void run() { for (int i = 0; i < 100; i++) { System.out.println("线程编号"+ID+"->执行打印"+i); } } } - 实现Runnable接口(需要重写run方法,不重写报错)
class runRunnable implements Runnable { String ID; public runRunnable(String ID) { this.ID = ID; } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("线程编号"+ID+"->执行打印"+i); } } }两种方式有什么区别?
public class ThreadTest {
public static void main(String[] args) {
// ThreadTestDemo td = new ThreadTestDemo("1");
// ThreadTestDemo td2 = new ThreadTestDemo("2");
//
// td.start();
// td2.start();
runRunnable run1 = new runRunnable("r1");
runRunnable run2 = new runRunnable("r2");
Thread r1 = new Thread(run1);
Thread r2 = new Thread(run2);
r1.start();
r2.start();
}
}
- 1.通过接口实现线程 会更加的灵活(有继承别的类的机会) 其本质是 线程任务执行类(这也是为什么 接口实现的线程 要通过Thread类才可以启动)
- 2.Thread类本质 是 线程管理类 (这也是为什么 接口实现的线程 要通过Thread类才可以启动)
--线程安全问题:
什么是线程安全问题?
线程安全问题指的是:不同线程 同时 访问修改 相同的数据 造成数据更新不及时
class MyThread implements Runnable{
static int counter = 0;
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
counter++;
}
}
}
public class ThreadSafety {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
Thread r1 = new Thread(t1);
Thread r2 = new Thread(t2);
Thread r3 = new Thread(t3);
r1.start();
r2.start();
r3.start();
try {
r1.join();
r2.join();
r3.join();
} catch (InterruptedException e) {
}
System.out.println(MyThread.counter);
}
}
本来想着counter的输出应该是30000,但是最后conunter的输出的数值是"随机的"并不是固定的30000这就是线程安全问题导致的
为什么?
线程r1,r2,r3共享进程资源,进程和其资源保存在堆内存中,每个线程会单独开辟一个栈内存空间用于存放数据和任务处理,那么在任务处理的过程中,线程就会从进程的堆内存中拷贝共享资源到自己的栈内存中在数据任务处理结束后,再将数据更新到堆内存中。

上面说的是一个线程的工作过程,如果有多个线程,拿取到的是同样资源(未及时更新)并执行相同操作更新呢?这就会导致一个或多个线程白执行任务(多个线程干的是完全相同(拿取的数据相同执行的操作相同))以导致线程安全问题
如何解决线程安全问题?
在最小粒度上,将整个操作原子化 可以使用 Java的隐式锁:synchronized 代码块 提供一个所有线程都可以看到的唯一对象
class MyThread implements Runnable{
static int counter = 0;
static Object lock = new Object(); //所有线程都可以看到的唯一对象
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
synchronized (lock) {
counter++;
}
}
}
}
public class ThreadSafety {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
Thread r1 = new Thread(t1);
Thread r2 = new Thread(t2);
Thread r3 = new Thread(t3);
r1.start();
r2.start();
r3.start();
try {
r1.join();
r2.join();//join本来是插队执行完,因为是执行完,所以这样用可以确保线程执行完毕
r3.join();
} catch (InterruptedException e) {
}
System.out.println(MyThread.counter);
}
}
如此通过 synchronized 锁住了++操作(上锁的线程执行完解锁后后面线程才可以执行)后面输出就是30000就解决了问题
346



被折叠的 条评论
为什么被折叠?



