自从用 Typora后,感觉csdn越来越…这学期以后更新随缘了,算法类为了督促自己还是会更新,不过现在真没啥时间,数暑假必刷算法
Java进程与线程
程序:是含有指令和数据的文件, 被存储在磁盘或其他的数据存储 设备中,也就是说程序是静态的 代码。 进程:是程序的一次执行过程, 是代码在数据集合上的一次运行 活动,是系统进行资源分配和调 度的基本单位。
进程是资源发配的独立单位
分配进程
线程是调度执行的独立单位
线程:是进程的一个执行路径, 一个进程中至少有一个线程,进 程中的多个线程共享进程的资源
线程并发完成进程速度更快,快速推进进程
JAVA对线程封装
? currentThread()---获得当前CPU执行的线程
Class Thread
getId()返回线程的标识符
getName(返回线程名字)
getPriority()返回线程优先级
程序运行时变为进程,进程执行产生线程
线程的启动与运行
进程一创建就会有堆和方法区会产生一个主线程,完成
package one;
public class Qq {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
LTThread ltThread=new LTThread();
ltThread.setName("聊天");
ltThread.start();
SCThread scThread=new SCThread();
scThread.setName("上传");
scThread.start();
}
}
如果是Qq qq=new Qq();
qq.LT();
qq.SC();
运行方法时分别调用了什么进程?都是调用主线程,一个进程解决
如何实现同时?并行操作
可以让聊天单独用一个线程这样就可以交替的
在原有进程的基础下创建子类进程
package one;
public class LTThread extends Thread{
@Override
public void run() {
for (int i = 1; i < 101; i++) {
System.out.println(Thread.currentThread().getName()+":聊天进行进度"+i+"%");
}
}
}
创建线程
继承的方法创建线程
package two;
public class T1 extends Thread{
public T1(String name) {
super(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
System.out.println(this.getName());
System.out.println("我是新的线程");
}
}
package two;
public class Test1 {
public static void main(String[] args) {
T1 t1=new T1("new");
t1.setPriority(10);
t1.start();
}
}
实现接口创建进程
package two;
public class T2 implements Runnable{
public static int a=100;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+a--);
}
}
}
package two;
public class Test2 {
public static void main(String[] args) {
T2 t2=new T2();
Thread thread=new Thread(t2);
第二次思考--接收一个含有具体实现方法的接口,让之成为进程
thread.start();
T2 t3=new T2();
Thread thread1=new Thread(t3);
thread1.start();
}
}
使用Callable和Future创建线程
package two;
import java.util.concurrent.Callable;
public class T3 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName());
int sum=0;
for(int i=1;i<11;i++)
sum+=i;
return sum;
}
}
package two;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test3 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
T3 t3=new T3();
FutureTask<Integer> futureTas=new FutureTask<Integer>(t3);
第一个引入接口得到返回值类型,方法体作为进程的基础,该返回值用于进程结束的一些操作
然后作为参数传入接口,具有进程功能,和获取返回值的能力,获取进程自身的返回值的能力,最后作为参数传入Thread主接口,实现具有获取自身返回值的进程功能
Thread thread=new Thread(futureTas,"test1");
thread.start();
system.out.println(futureTas.get());
System.out.println(futureTas.get());
Thread thread1=new Thread(futureTas,"test2");
thread1.start();
System.out.println(futureTas.get());
}
}
如果对象需要返回值,那么这种进程只会执行第一个
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
线程一执行就调度这种方法—call–线程执行体
使用Future Task类包装这种线程执行类,该接口封装了Callable对象的call()方法的返回值,这个接口取得返回值,而RunnableFuture 实现了线程接口与可取返回值的接口
第二次思考–实现一个具有返回值的接口,作为进程方法体,第二个接口Future Task包装方法与返回值,进程接口Thread实现作为容器控制进程调度
线程会返回一个结果
优缺点
-
采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。 -
使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
继承方式,单继承,无法继承其他类
接口式–解决多继承
需要返回值与不使用返回值
进程的几种特殊实现方式
package two;
public class Test4 {
public static void main(String[] args) {
new Thread() {@Override
public void run() {
System.out.println("我是新的线程");
}
}.start();
}
} 线程类中匿名子类,重写run方法,以匿名的方式实现线程
package two;
public class Test5 {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是新的线程");
}
}).start();
}
}
匿名接口形式
package two;
public class Test6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
new Thread(()-> {System.out.println("我是新的线程");}).start();//
}
}
线程直接接收方法体内容
package two;
public class Test7 extends Thread{
public static void main(String[] args) {
// TODO Auto-generated method stub
Test7 test7=new Test7();
test7.start();//线程测试类 非重点
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("我是新线程");
}
}
package two;
public class Test8 implements Runnable
{public static void main(String[] args) {
// TODO Auto-generated method stub
Test8 test8=new Test8();
Thread t1=new Thread(test8); //测试接口将接口传入进程类中
t1.start();
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("我是新的线程");
}
}
线程生命周期
先实例化线程对象,start
就绪状态 —除了cpu的所有资源
获得CPU转向运行状态,单核指cpu个数
运行状态–线程的死亡或者运行中出现异常线程也结束
运行到就绪,跳转,比如计组中中断
阻塞态,暂时缺乏什么设备,到了后到达就绪态
线程生命周期转换过程
并发每次结果不一样
还记得搞笑的睡眠排序
package four;
public class T2 implements Runnable{
@Override
public void run() {
Long s=System.currentTimeMillis();
System.out.println("开始了");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束了");
System.out.println("用时毫秒:"+ (System.currentTimeMillis()-s));
}
}
package four;
public class T3 implements Runnable{
@Override
public void run() {
for (int i = 1; i < 100; i++) {
System.out.println(i);
}
}
}
package four;
public class Test3 {
public static void main(String[] args) throws InterruptedException {
T3 t3=new T3();
Thread thread=new Thread(t3,"测试");
thread.start();
thread.join();
System.out.println("main线程结束了");
}
}
如果没有join那肯定在分配cpu之前就输出main线程结束语句了
线程的同步问题
进程完成了一些对线程的调度控制—真跟K8S那样啊 容器
还使用进程中的一些共享变量
会出现什么问题?
一个共享变量被同时使用或写入时,会出现什么问题?
线程1失去cpu–
线程三顶上
注意线程1中的私有值,多个线程并发访问引发脏数据
立刻写入cpu让其它进程中副本数据立刻清空,必须从主内存中取得新数据
package three;
public class TestVo extends Thread{
public static boolean stop=false;
@Override
public void run() {
System.out.println("我开始了");
while (!stop) {
}
System.out.println("我结束了");
}
public static void main(String[] args) throws InterruptedException {
TestVo testVo=new TestVo();
testVo.start();
stop=true;
}
}
分析stop是共享变量,打开主线程会让stop变为true子线程结束
原子性问题
语句分为好几个指令,会有中断现象,a+1为好几个指令,中断失去cpu
中断应保护现场
两个线程 因为cpu切换和原子性指令都读出a=10,结果算出11
写误差
如何解决原子性问题
临界区只能由一个线程进入
所谓临界资源 因中断必须保护现场的
比如访问a
锁机 开锁与关锁,只有一个进程能拿到锁,不用释放
package three;
public class T1 implements Runnable {
static Object object = new Object();
synchronized public void f1() {
System.out.println("测试");
synchronized (object) {
System.out.println(Thread.currentThread().getName() +"开始了");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "结束了");
}
}
@Override
public void run() {
f1();
}
}
下面对应
synchronized (object){
}
package three;
public class Testsy {
public static void main(String[] args) {
T1 t=new T1();
T1 tt=new T1();
Thread t1=new Thread(t,"测试1");
Thread t2=new Thread(t,"测试2");
Thread t3=new Thread(tt,"测试3");
t1.start();
t2.start();
t3.start();
}
}
怎么锁住整体,让f1变为静态方法,不是针对对象要锁,针对类要锁
那么如果不整体互斥该怎么办?就是在f1中并不是所有的代码都是互斥访问的,如果方法静态,那么进程中不互斥的代码无法同步执行
对方法块的处理
有时候你烦就烦在学完了给你介绍个更牛逼的 只能找邻居要钥匙,只能有一个人进入家)相当于把那些要用这个方法的对象互斥了,因为这个静态类的锁是整个共有的,只有一把
}
```java
package three;
public class Testsy {
public static void main(String[] args) {
T1 t=new T1(); //方法所在实例对象为锁
T1 tt=new T1();
Thread t1=new Thread(t,"测试1");
Thread t2=new Thread(t,"测试2");
Thread t3=new Thread(tt,"测试3");
t1.start();//锁住
t2.start();//要不到锁,f1中不允许同时有两个线程
t3.start();//这个锁是 tt的实例对象,是tt对象中f1的锁,可以执行
}
}
怎么锁住整体,让f1变为静态方法,不是针对对象要锁,针对类要锁
那么如果不整体互斥该怎么办?就是在f1中并不是所有的代码都是互斥访问的,如果方法静态,那么进程中不互斥的代码无法同步执行
对方法块的处理
有时候你烦就烦在学完了给你介绍个更牛逼的
|