2025年java 编程基础篇

java 编程基础篇1 1 进程与线程 进程 系统进行资源分配和调度的基本单位 线程 CPU 分配的基本单位 一个进程包含很多个线程 1 2 线程的创建和运行 三种方式 实现 Runnable 接口 继承 Thread 类 使用 FutureTask 方式 实现 Callable 接口中的 call 方法 import java util concurrent Callable import java util

大家好,我是讯享网,很高兴认识大家。



1.1进程与线程

进程:系统进行资源分配和调度的基本单位

线程:CPU分配的基本单位

一个进程包含很多个线程

1.2线程的创建和运行

三种方式:实现Runnable接口、继承Thread类、使用FutureTask方式(实现Callable接口中的call方法)

import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallerTask implements Callable<String> { @Override public String call() throws Exception { return "您好啊"; } public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> futureTask = new FutureTask<String>(new CallerTask()); new Thread(futureTask).start(); String s = futureTask.get(); System.out.println(s.toString()); } }
讯享网

1.3线程通知与等待

线程的状态:

new:就绪,就是等待执行

runnable:执行

waiting:在等待队列里面

timewaiting:有时间的等待

blocked:阻塞状态

terminate:执行完毕或者中断了,反正就是终了

wait函数

手动实现消费者和生产者-----不太会,就写了一个脑残的版本!

讯享网import collection.Fu; import com.sun.xml.internal.bind.v2.model.annotation.RuntimeAnnotationReader; import java.util.LinkedList; import java.util.Queue; public class ProducerAndConsumer{ public Queue<Integer> queue = new LinkedList<>(); public int MAX_SIZE = 10; public class Producer1 implements Runnable{ @Override public void run() { synchronized (queue){ while (true){ while (queue.size() == MAX_SIZE){ try { System.out.println("做好了"); queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.add(1); System.out.println("做了一个"); queue.notify(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } public class Consumer1 implements Runnable{ @Override public void run() { synchronized (queue){ while (true){ while (queue.size() == 0){ try { System.out.println("吃完了" + queue.size()); queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.remove(); System.out.println("吃了一个"); queue.notify(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } public static void main(String[] args) { ProducerAndConsumer procon = new ProducerAndConsumer(); Producer1 producer1 = procon.new Producer1(); Consumer1 consumer1 = procon.new Consumer1(); Thread t_p = new Thread(producer1); Thread t_c = new Thread(consumer1); t_c.start(); t_p.start(); } }

wait(long timeout)函数

public class WaitTimeOut { public static void main(String[] args) { String lock = "锁"; new Thread(new Runnable() { @Override public void run() { synchronized java 编程基础篇 (lock){ System.out.println("我开始了"); try { lock.wait(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我好了"); } } }).start(); new Thread(new Runnable() { @Override public void run() { synchronized (lock){ System.out.println("我直接冲"); } } }).start(); } } / * 我开始了 * 我直接冲 * 我好了 */

wait(long timeout, int nanos)函数

后面的nanos其实没什么用,就是nanos>0时,timeout + 1;没什么实际作用的

notify()函数

看上面的消费者与生产者例子:

当线程进入wait队列之后,在别的线程中,对象.notify()。就会在以这个对象为锁的wait队列里头唤醒一条线程。

notifyAll()函数

唤醒所有的wait队列里头的线程,然后再进行相互竞争锁的局面。害,其实我觉得没什么用的。

join()函数

在main线程中写:线程1.join()

表示:将main线程加到线程1的末尾,所以只有线程1执行完成之后,main线程才能执行。

sleep()函数

简单的让线程睡一会

yield函数

当前线程让出cpu,但是cpu不一定会让出去,只是想让罢了;

区别:

除了sleep、yield、join可以在随便一个调用外,其它的只能在同步代码快里头使用。没有竞争,哪里来的wait和唤醒呢。

线程中断

void interrupt()

随便一个地方中断线程,也就是给线程设置一下中断标志;如果此时线程在wait、sleep、join;那就最好了,直接抛出异常返回了。

boolean isInterrupted()

判断当前线程的中断标志为是否为真:是,返回true;否:返回false

boolean interrupted()

判断当前线程是否被中断,如果是返回true,然后清除中断标志!!!!,否就直接返回false;其实感觉并没有什么用;

讯享网public class InterruptedTest{ public static void main(String[] args) { String lock = "锁住"; Thread t1 = new Thread(new Runnable() { @Override public void run() { synchronized (lock) { System.out.println("兄弟,我来了"); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("我被杀了"); } } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我是杀手,t1你去死吧"); t1.interrupt(); } }); t1.start(); t2.start(); } }

线程上下文切换

就是切来切去呗;

线程死锁

条件:

  • 互斥条件,就是需要竞争资源
  • 请求并持有条件:就是要了还想要
  • 不可剥夺条件:资源使用完之前不能剥夺
  • 环路等待条件:必须形成一个线程资源的环形链

避免死锁:

  • 破坏请求并持有
  • 破坏环路等待

守护线程和用户线程

守护线程

jvm的线程

用户线程

自己写的线程

手写线程.setDaemon(true):设置成守护线程

ThreadLocal

创建一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。当多个线程操作这个变量时,实际操作的是自己本地内存里面的变量,从而避免线程安全问题。

创建一个ThreadLocal变量后,每个线程都会复制一个变量到自己的本地内存

public class ThreadLocalTest { static void print(String str){ //但因当前线程本地内存中的localVariable变量的值 System.out.println(str + ":" + localVariable.get()); } //创建ThreadLcoal变量 static ThreadLocal<String> localVariable = new ThreadLocal<>(); public static void main(String[] args) { //创建线程one Thread threadOne = new Thread(new Runnable() { @Override public void run() { //设置线程one中的本地变量localVariable的值 localVariable.set("one"); print("threadOne"); System.out.println("one remove after" + ":" + localVariable.get()); } }); //创建线程one Thread threadTwo = new Thread(new Runnable() { @Override public void run() { //设置线程one中的本地变量localVariable的值 localVariable.set("two"); print("threadTwo"); System.out.println("two remove after" + ":" + localVariable.get()); } }); threadOne.start(); threadTwo.start(); } } / * threadOne:haha * threadTwo:two * two remove after:two * one remove after:haha */

Thread类中有一个threadLocals和inheritableThreadLocals,它们是ThreadLocalMap类型的变量,而ThreadLocalMap是一个定制化的HashMap。

默认情况下,这两个变量都为null,只有当前线程第一次调用ThreadLocal的set或者get方法时才会创建它们。

其实每个线程的本地变量不是存放在ThreadLocal的实例里面,而是存放在调用线程的ThreadLocals变量里面。

也就是说,ThreadLocal类型的本地变量放在具体的线程空间里面。ThreadLocal类就是也给工具壳,它通过set方法把value值放入调用线程的threadLocals里面并存放起来;当调用的线程用get方法时,再从当前线程的threadLocals里面拿出来。

说了那么多:简单说就是:每个线程中有一个ThreadLocals变量:存放着很多ThreadLocal变量;threadLocals结构:hashMap<threadLocal, value>;

set的步骤

(1)获取当前的线程

(2)获取当前线程的threadLocals,也就是那个map

(3)map不为null,就将 <threadLocal的hash值作为key,值>,存入threadLocals中

(4)map为空的,那好说了,就创建一个,并进行(3)

get步骤:其实就是将threadLocal的hash值作为key,在threadLocals的map中查找,如果这源码看不懂,那也没办法了。

这个就是,如果get操作时,发现threadlocals为空,那就是找不到!那么就初始化threadLocals!!!!!!!

然后,这次没找到;那么将《threadlocal的hash值,null》插入到threadLocals中,不懂这样做有什么意义,骗自己嘛?

都这样了,就是threadlocals的map删除threalocal

不会真有人看不懂ThreadLocal的源码吧。好吧,我也是看了好久。

主要难点是没搞清楚:

Thread类中的threadLocals对应好多的ThreadLocal

还有这一句:

Thread t = Thread.currentThread();

怎么获取当前线程的?其实很简单,因为threadLocal.set()是在该线程的run方法中执行的,你说能不能获得当前的线程是哪个呢?

ThreadLocal不支持继承性

就是简单说,每个线程中的ThreadLocal都不是互通的!其实废话了!

但是你不会忘记了

见名知意:这个东东应该就是继承用的!

当然就有那么一个InheriatableThreadLocal类和inheritableThreadLocals对应咯

其实方法都差不多的,就是后者重写了ThreadLocal中的一些方法;简单说就是创建子线程的时候,会将父亲的inhereatableThreadLocals中的本地变量赋值到子线程中。

将父亲的inheriatableThreadLocal的赋值卸载儿子的后面结果:

public class ThreadLocalTest { public static void main(String[] args) { InheritableThreadLocal<String> fu1 = new InheritableThreadLocal<>(); InheritableThreadLocal<String> fu2 = new InheritableThreadLocal<>(); InheritableThreadLocal<String> zi1 = new InheritableThreadLocal<>(); InheritableThreadLocal<String> zi2 = new InheritableThreadLocal<>(); //创建线程one Thread threadOne = new Thread(new Runnable() { @Override public void run() { //设置线程one中的本地变量localVariable的值 zi1.set("儿子1"); zi2.set("儿子2"); System.out.println(zi1.get()); System.out.println(zi2.get()); System.out.println(fu1.get()); System.out.println(fu2.get()); } }); fu1.set("爸爸1"); fu2.set("爸爸1"); threadOne.start(); } } /结果 * 儿子1 * 儿子2 * null * null */

将父亲的inheriatableThreadLocal的赋值卸载儿子的前面结果:

public class ThreadLocalTest { public static void main(String[] args) { InheritableThreadLocal<String> fu1 = new InheritableThreadLocal<>(); InheritableThreadLocal<String> fu2 = new InheritableThreadLocal<>(); InheritableThreadLocal<String> zi1 = new InheritableThreadLocal<>(); InheritableThreadLocal<String> zi2 = new InheritableThreadLocal<>(); fu1.set("爸爸1"); fu2.set("爸爸1"); //创建线程one Thread threadOne = new Thread(new Runnable() { @Override public void run() { //设置线程one中的本地变量localVariable的值 zi1.set("儿子1"); zi2.set("儿子2"); System.out.println(zi1.get()); System.out.println(zi2.get()); System.out.println(fu1.get()); System.out.println(fu2.get()); } }); threadOne.start(); } } /结果 * 儿子1 * 儿子2 * 爸爸1 * 爸爸1 */

那么可以总结了:也就是子线程的inheritable初始化的那么一下将父线程的inheriatableThreadLocals的值复制一下,之后就不再保持一致了。

小讯
上一篇 2025-01-01 09:13
下一篇 2024-12-27 15:12

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/10791.html