JAVA 多线程

从想法到零件:手把手拆解一个汽车功能如何从PRD写到SSTS和CTS 本文详细拆解了汽车电子需求从市场文档(MRD)到零部件技术规范(CTS)的完整流程,以雨天自动关窗功能为例,展示了PRD、SSTS和CTS的编写要点与交互设计。文章重点解析了系统分解的艺术和零部件落地的精确参数要求,为汽车电子工程师提供了从概念到实现的全流程实践指南。 阅读详情
一、进程与线程


个人所理解进程与线程的关系,如图:


        进程是资源的拥有者,所以切换中系统要付出较大的时空开销,如图中A-->B所占用的时间片段。因此导致系统中的进程数和切换频率不宜过高,限制了并发程度的提高,而线程不属于资源被分配的单位,只是共享所属进程的资源,因此可以轻装上阵,线程间的切换开销要比进程少得多,由于资源是共享的所以进程间的通信也比进程间通信容易得多。


二、两种多线程的方式


1.继承Thread类复写run方法

public class ThreadDemo  {
	public static void main(String[] args) {
		MyThread thread1=new MyThread();
		//thread1.setName("这里定义线程名");
		thread1.start();//启动该线程 注:此时共有main和thread1两个线程
		
		
	}
}
class MyThread extends Thread{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		//super.run();
		
		System.out.println("这里写线程所要执行的代码");
		System.out.println(Thread.currentThread().getName()); //Thread.currentThread() 获取当前线程对向
	}
//	public MyThread(String name){
//		super.setName(name);初始化同时命名线程
//	}
}


2.实现Runnable接口

public class ThreadDemo {
	public static void main(String[] args) {
		MyRunnable runnable = new MyRunnable();
		Thread thread = new Thread(runnable);
		thread.setName("这里定义线程名");
		thread.start();// 启动该线程 注:此时共有main和thread两个线程

	}
}

class MyRunnable implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("这里写线程所要执行的代码");
	}

}


三、两种方式的比较(以售票为例,多个线程同时对Ticket类的实例对象进行操作)


1.以继承Thread类方式

        如果以这种方式实现多线程操作共享数据,需要将共享资源作为继承于Thread的类成员变量,并提供set方法或在构造方法中予以赋值,而每一个Thread的实例set进同一个资源的载体。如代码中:MyThread继承Thread类,多个MyThread的实例即多个线程操作Ticket的一个实例,则将Ticket类作为MyThread的成员

class Ticket {
	private int num;//定义票数

	public Ticket(int num) {
		this.num = num;
	}

	/**
	 * 提供售票方法,每次执行票数减一
	 * @return 
	 */
	public synchronized void sell() {
		if (num > 0)
		System.out.println(Thread.currentThread().getName() + "售出一张,剩余" + --num);
		else
		System.out.println("对不起,票已售完");
	}
	

	public int getNum() {
		return num;
	}
}

class MyThread extends Thread {
	private Ticket ticket;//将要操作的资源类作为成员变量,并提供set方法,将实例对象set进来

	public void setTicket(Ticket ticket) {
		this.ticket = ticket;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			synchronized (ticket) {
				if (ticket.getNum() == 0)
					break;
				ticket.sell();
			}
		}
	}
}

public class ThreadDemo {
	public static void main(String[] args) throws InterruptedException {

		Ticket ticket = new Ticket(10000);
		MyThread thread1 = new MyThread();
		MyThread thread2 = new MyThread();
		MyThread thread3 = new MyThread();
		thread1.setTicket(ticket);
		thread2.setTicket(ticket);
		thread3.setTicket(ticket);// 这里三个新创建的并发线程都要set进同一个资源(同一个实例对象)
		thread1.start();
		thread2.start();
		thread3.start();
		
	}
}

2.以实现Runnable接口的方式(列举多种写法)

  • 在实现Runnable接口的同时继承要操作的共享资源类,如代码中新建MyRunnable extend Ticket implements,但Ticket中票数num要设为protect
class Ticket {
	protected int num;// 定义票数

	public Ticket(int num) {
		this.num = num;
	}

	/**
	 * 提供售票方法,每次执行票数减一
	 * 
	 * @return
	 */
	public synchronized void sell() {
		if (num > 0)
			System.out.println(Thread.currentThread().getName() + "售出一张,剩余" + --num);
		else
			System.out.println("对不起,票已售完");
	}

	public int getNum() {
		return num;
	}
}

class MyRunnable extends Ticket implements Runnable{

	public MyRunnable(int num) {
		super(num);
		// TODO Auto-generated constructor stub
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			synchronized (this) {
				if(num==0)break;
				sell();
			}
		}
	}
}
public class ThreadDemo{
	public static void main(String[] args) {
		Runnable myRunnable=new MyRunnable(10000);
		Thread thread1=new Thread(myRunnable);
		Thread thread2=new Thread(myRunnable);
		Thread thread3=new Thread(myRunnable);
		thread1.start();
		thread2.start();
		thread3.start();
		
	}
}

  •  仅实现Runnable接口不继承资源类,而是将资源类作为成员变量set或构造函数中赋值
class Ticket {
	privateint num;// 定义票数

	public Ticket(int num) {
		this.num = num;
	}

	/**
	 * 提供售票方法,每次执行票数减一
	 * 
	 * @return
	 */
	public synchronized void sell() {
		if (num > 0)
			System.out.println(Thread.currentThread().getName() + "售出一张,剩余" + --num);
		else
			System.out.println("对不起,票已售完");
	}

	public int getNum() {
		return num;
	}
}

class MyRunnable implements Runnable{
	private Ticket ticket;

	public void setTicket(Ticket ticket) {
		this.ticket = ticket;
	}
	public MyRunnable(Ticket ticket) {
		// TODO Auto-generated constructor stub
		this.ticket=ticket;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			synchronized (this) {
				if(ticket.getNum()==0)break;
				ticket.sell();
			}
		}
	}
}
public class ThreadDemo{
	public static void main(String[] args) {
		Runnable myRunnable = new MyRunnable(new Ticket(10000));
		Thread thread1 = new Thread(myRunnable);
		Thread thread2 = new Thread(myRunnable);
		Thread thread3 = new Thread(myRunnable);
		thread1.start();
		thread2.start();
		thread3.start();

	}
}

  • 直接用共享资源类去实现Runnable接口,这种方法还可以继续继承其他类
class Ticket implements Runnable {
	privateint num;// 定义票数

	public Ticket(int num) {
		this.num = num;
	}

	/**
	 * 提供售票方法,每次执行票数减一
	 * 
	 * @return
	 */
	public synchronized void sell() {
		if (num > 0)
			System.out.println(Thread.currentThread().getName() + "售出一张,剩余" + --num);
		else
			System.out.println("对不起,票已售完");
	}

	public int getNum() {
		return num;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			synchronized (this) {
				if (num == 0) break;
				sell();
			}
		}
	}
}

public class ThreadDemo {
	public static void main(String[] args) {
		Runnable ticket = new Ticket(10000);
		Thread thread1 = new Thread(ticket);
		Thread thread2 = new Thread(ticket);
		Thread thread3 = new Thread(ticket);
		thread1.start();
		thread2.start();
		thread3.start();

	}
}

        由此可见,实现Runnable这种方式除了可以避免java单继承的局限外,写法多变,更为灵活,可以根据实际情况采取相应的方法,在实际开发中也更为常用。

四、线程的状态及转换



  • 初始化状态:调用 new方法产生一个线程对象后、调用 start 方法前所处的状态。
  • 就绪状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入就绪状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到就绪状态。多个线程间对cpu的争夺,都是以该状态为前提,即只有就绪状态的线程才有资格争取cpu的执行。
  • 运行状态:线程调度程序从就绪线程池中选择一个线程执行后所处的状态。这也是线程进入运行状态的唯一一种方式。
  • 等待/阻塞/睡眠状态:这是线程有资格运行时它所处的状态但非就绪。实际上这个三状态组合为一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。换句话说,它是可运行的,但是如果某件事件出现,他可能返回到可运行状态。
  • 消亡状态:当线程的run()方法完成时的状态。

五、常用的进程控制语句

1.Thread.sleep()
class MyRunnable implements Runnable{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			Thread.sleep(1000);
			System.out.println("Thread.sleep(这里是毫秒)");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
2.设置优先级
public class ThreadDemo  {
	public static void main(String[] args) throws Exception{
		Runnable myrRunnable=new MyRunnable();
		Thread thread1=new Thread(myrRunnable);
		Thread thread2=new Thread(myrRunnable);
		thread1.setPriority(7);//这里可设优先级1-10代表由低到高 
		thread1.start();
		thread2.start();
	}
}
线程默认优先级是5,Thread类中有三个常量,定义线程优先级范围:
static int MAX_PRIORITY 线程可以具有的最高优先级。 
static int MIN_PRIORITY 线程可以具有的最低优先级。 
static int NORM_PRIORITY 分配给线程的默认优先级。
3.线程让步yield()
    之前提到所有可争夺cpu执行权的线程都应该是就绪状态,但是如果正在执行的线程一只占用cpu不主动释放,会导致就绪线程吃内的线程在一段时间内得不到执行,而该时间内总是由运行着的线程霸占。结果是cpu在一个线程上处理一大批数据后,才切换到另一个线程上去。而yield()方法则是让当前线程主动放权,即有运行状态主动转为就绪状态,这样线程切换的频率大大提高,效果是cpu每在一个线程上处理几条数据就切换到另一个线程。


4.join()

Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作。下面是一个两个线程向同一个数组中添加元素的例子,要求两线程向该数组添加结束后,主线程再打印该数组的元素。
public class JoinDemo{
	public static void main(String[] args) throws Exception {
		int[] nums = new int[6];
		Add add = new Add(nums);
		Thread thread1 = new Thread(add);
		Thread thread2 = new Thread(add);
		thread1.setName("线程1");
		thread2.setName("线程2");
		thread1.start();
		thread2.start();//此时共main、thread1、thread2三个线程
		thread1.join();//main读到这条与语句后,main只有在thread1结束后再运行(实际是main的线程栈追加到thread1的末尾)。此时只有thread1和thread2在运行
		thread2.join();//main方法读这条语句时刻,运行的语句有main、thread2,读完该条语句后,只有thread2运行结束后才执行main
		System.out.println(Arrays.toString(nums));//此时只有main线程
	}
}

class Add implements Runnable {

	private int[] nums;
	
	@Override
	public  void run() {
		// TODO Auto-generated method stub
		 
		try {
			mainDo();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void mainDo() throws InterruptedException {
		for (int i = 0; i < 3; i++) {
			synchronized (this) {
			for (int j = 0; j < nums.length; j++) {
				
					Thread.sleep(new Random().nextInt(500));
					if (nums[j] == 0) {
						nums[j] = new Random().nextInt(999) + 1;
						System.out.println(Thread.currentThread().getName() + "向num[" + j + "]添加" + nums[j]);
						break;
					}
				}
			}
		}
	}

	public Add(int[] nums) {

		this.nums = nums;

	}
 
}
通过以上11行和12行的语句使得打印结果如下:


而不使用join方法结果是在添加数据前打印出空数组




六、线程安全

依然以常见的售票为例,这里设票数只有一张,两个线程出售,运行如下代码:
class Ticket {
	private int num;//定义票数

	public Ticket(int num) {
		this.num = num;
	}

	/**
	 * 提供售票方法,每次执行票数减一
	 * @return 
	 */
	public void sell() {
		if (num > 0)
		System.out.println(Thread.currentThread().getName() + "售出一张,剩余" + --num);
	}
	

	public int getNum() {
		return num;
	}
}

class MyThread extends Thread {
	private Ticket ticket;//将要操作的资源类作为成员变量,并提供set方法,将实例对象set进来

	public void setTicket(Ticket ticket) {
		this.ticket = ticket;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {		
				if (ticket.getNum() <= 0)
					break;
				ticket.sell();
				Thread.yield();
		}
	}
}
运行结果:

出现-1张余票的原因是两个线程同时在操作共享数据票数,然而在A线程执行一半,另一个进程抢占到cpu执行权,这是调度程序会对A发出中断,A响应中断,将当前全部状态进栈,接下来执行线程B,线程B又对票数进行修改,当A线程再次执行时,将之前栈内状态出栈,恢复被中断前的状态继续执行,结果就会出现这种情况。解决办法是在一个线程对共享数据读或写的过程中不被中断。

线程同步的方法:


1.同步代码块,代码块内的语句执行过程不会被中断
synchronized(obj)
{ //obj表示同步监视器,是同一个同步对象,该例中可以将共享资源ticket作为监视器,个人理解要保证同步的线程监视器对象必须是同一个
/**.....
TODO SOMETHING
*/
}
2.方法的同步,加入修饰符synchronized ,监视器为this,格式如下,
synchronized 返回值类型 方法名(参数列表){
/**.....
TODO SOMETHING
*/
}
注:由于在调用静态方法时,对象实例不一定被创建,因此,就不能使用this作为监视器,而是该静态方法所属类的字节码。
常见的延迟单例模式中监视器就为Single.class

class Single {
	private Single() {
		// TODO Auto-generated constructor stub
	}

	private static Single instance = null;

	public static Single getInstance() {
		if (instance == null) {
			synchronized (Single.class) {
				if (instance == null)
					instance = new Single();
			}

		}
		return instance;
	}

}
3.ReentrantLock代替synchronized 

class MyRunnable extends Ticket implements Runnable{
	ReentrantLock lock=new ReentrantLock();
	public MyRunnable(int num) {
		super(num);
		// TODO Auto-generated constructor stub
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			lock.lock();
				if(num==0)break;
				sell();
			lock.unlock();
		}
	}
}


七、关于死锁

关于汤子瀛版操作系统中描述的哲学家进餐问题,五位哲学家围坐在圆桌进餐,但每人仅右手边放置一只筷子,哲学家只有在同时获得两只筷子时才会进餐,进餐完毕释放两只筷子,不进餐时进行思考(等待),若有一位哲学家获得一只筷子,不会主动释放而是等待另一只筷子(请求保持),哲学家间不可抢夺筷子。如此循环,就有可能出现五个人手中各有一只筷子,在等待另一只筷子,造成再也无人进餐。这种情况就是死锁。

进程和线程发生死锁的必要条件:

对资源的互斥使用、不可强占、请求和保持、循环等待,当满足这四个条件时就有可能发生死锁,但是只要破坏其中任意一个条件就能避免思索。

Java多线程中出现死锁的例子(这里的资源指的是同步时的监视器对象,同步代码块使用监视器对象就是占有该资源):

class Resource {

	public static Object object1 = new Object();
	public static Object object2 = new Object();
	public static Object object3 = new Object();
	public static Object object4 = new Object();

}

class MyRunnable1 implements Runnable {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			synchronized (Resource.object1) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				synchronized (Resource.object2) {
					System.out.println("执行MyRunnable1.fun()");
				}
			}
		}
	}
}

class MyRunnable2 implements Runnable {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			synchronized (Resource.object2) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				synchronized (Resource.object1) {
					System.out.println("执行MyRunnable2.fun()");
				}
			}
		}
	}
}

public class ThreadDemo {
	public static void main(String[] args) {
		Runnable runnable1 = new MyRunnable1();
		Runnable runnable2 = new MyRunnable2();
		Thread thread1 = new Thread(runnable1);
		Thread thread2 = new Thread(runnable2);
		thread1.start();
		thread2.start();
	}
}
关于避免死锁,个人理解:对于上述代码中出现了thread1和thread2互斥使用资源object1和object2,并且相互等待(循环等待)对方线程占有的资源(锁),同时同步代码块也满足了请求保持和不可抢占。解决办法是可以将object1和object2两个资源(锁)封装成一个对象(整体)(锁)。这样可以避免循环等待。对应哲学家进餐问题中,将两只筷子封装成一套餐具,只有得到一套餐具时才可以进餐,在多线程中也应尽量避免锁的嵌套使用。以免造成循环等待的情况出现。


八、线程通讯

wait():让当前线程放弃监视器进入等待,直到其他线程调用同一个监视器并调用notify()或notifyAll()为止。
notify():唤醒在同一对象监听器中调用wait方法的第一个线程。
notifyAll():唤醒在同一对象监听器中调用wait方法的所有线程。

下面的例子是通过两个线程向一个数组内添加元素,通过线程间的通讯达到一个线程添加一个元素后,另一个线程再添加一个元素如此往复的效果。

import java.util.Arrays;
import java.util.Random;

public class ThreadTest {
	public static void main(String[] args) throws Exception {
		int[] arrary = new int[1000];
		Res res = new Res(arrary, false);
		Runnable r1 = new add1(res);
		Runnable r2 = new add2(res);
		Thread t1 = new Thread(r1);
		Thread t2 = new Thread(r2);
		t1.start();
		t2.start();
		t1.join();
		t2.join();
		//main线程最后打印结果
		System.out.println(Arrays.toString(arrary));

	}

}

/**
 * @author Mr
 * 资源类,封装有数组和线程间通讯的标志位
 */
class Res {
	private int[] array;
	private boolean sign;

	public int[] getArray() {
		return array;
	}

	public void setArray(int[] array) {
		this.array = array;
	}

	public boolean isSign() {
		return sign;
	}

	public void setSign(boolean sign) {
		this.sign = sign;
	}

	public Res(int[] array, boolean sign) {
		// TODO Auto-generated constructor stub
		this.array = array;
		this.sign = sign;
	}
}

/**
 * @author Mr
 *	线程1负责向数组的前半部分添加元素
 */
class add1 implements Runnable {
	private Res res;

	public add1(Res res) {
		// TODO Auto-generated constructor stub
		this.res = res;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = 0; i < res.getArray().length / 2; i++) {
			synchronized (res) {
				if (res.isSign())
					try {
						res.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				int num = new Random().nextInt(99) + 1;
				res.getArray()[i] = num;
				System.out.println(Thread.currentThread().getName() + "向array["
						+ i + "]添加" + num);
				res.setSign(true);
				res.notify();
			}
		}
	}
}

/**
 * @author Mr
 *	线程2负责向数组的后半部分添加元素
 */
class add2 implements Runnable {

	private Res res;

	public add2(Res res) {
		// TODO Auto-generated constructor stub
		this.res = res;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = res.getArray().length / 2; i < res.getArray().length; i++) {
			synchronized (res) {
				if (!res.isSign())
					try {
						res.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				int num = new Random().nextInt(99) + 1;
				res.getArray()[i] = num;
				System.out.println(Thread.currentThread().getName() + "向array["
						+ i + "]添加" + num);
				res.setSign(false);
				res.notify();
			}
		}
	}
}

效果如下:


另外在jdk1.5后提供了新的方法以代替锁和wait、notify、notifyall方法,常见的生产者与消费者的例子,其中三个生产者线程,两个消费者线程:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadTest{
	public static void main(String[] args) {

		Res res = new Res("豆浆", 0);
		Runnable r1 = new producer(res);
		Runnable r2 = new customer(res);
		Thread t1 = new Thread(r1);
		Thread t2 = new Thread(r1);
		Thread t3 = new Thread(r1);

		Thread t5 = new Thread(r2);
		Thread t6 = new Thread(r2);

		t1.start();
		t2.start();
		t3.start();

		t5.start();
		t6.start();

	}
}

class Res {
	private String name;// 商品(资源)名
	private int no;// 商品编号
	private boolean sign;
	private final Lock lock = new ReentrantLock();
	private Condition condition_con = lock.newCondition();
	private Condition condition_pro = lock.newCondition();

	public Res(String name, int no) {
		// TODO Auto-generated method stub
		this.name = name;
		this.no = no;
	}

	/**
	 * 生产
	 */
	public void pro() {
		lock.lock();
		while (sign) {
			try {
				condition_pro.await();// 生产相关线程wait
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName() + "生产了" + name
				+ ++no);
		sign = true;
		condition_con.signalAll();// 唤起消费相关线程
		lock.unlock();
	}

	/**
	 * 消费
	 */
	public void cus() {
		lock.lock();
		while (!sign) {
			try {
				condition_con.await();// 消费相关线程wait
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out
				.println(Thread.currentThread().getName() + "消费了" + name + no);
		sign = false;
		condition_pro.signalAll();// 唤起生产相关线程
		lock.unlock();
	}
}

/**
 * @author Mr 生产者
 */
class producer implements Runnable {
	private Res res;

	public producer(Res res) {
		// TODO Auto-generated constructor stub
		this.res = res;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			res.pro();
		}
	}
}

/**
 * @author Mr 消费者
 */
class customer implements Runnable {
	private Res res;

	public customer(Res res) {
		// TODO Auto-generated constructor stub
		this.res = res;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			res.cus();
		}
	}
}




STM32入门教程:自动门控制 通过这个简单的示例,我们展示了如何使用STM32微控制器来实现一个简单的自动门控制系统。如果有物体靠近门口,我们会改变doorState的值,并使用controlServoMotor函数来控制舵机电机的转动。具体的引脚连接可以根据您的具体硬件来定,例如将红外传感器的输出引脚连接到GPIOA_PIN0引脚。同样,具体的引脚连接可以根据您的具体硬件来定,例如将舵机的控制引脚连接到GPIOA_PIN1引脚。首先,我们需要包含必要的库文件和引用。然后,我们需要定义一些函数来处理红外传感器的输入和舵机电机的输出。 阅读详情

相关推荐

抖音小游戏(IAA)巨量引擎投放指南

摘要:本文详细介绍了在巨量引擎平台投放小游戏广告的完整流程,包括五个关键步骤:1)添加小游戏资产,填写ID等信息并等待审核;2)添加事件管理,配置激活和关键行为事件;3)通过橙子建站创建落地页,设置跳转链接;4)新建广告项目,选择小程序推广目标;5)完成广告创建。

分享前端工程化、AI 应用、Agent 开发与大模型实践! 4507

java runnable main_一脚踩进java之基础篇44——线程Thread和Runnable

一、Thread类1.1 该如何创建线程呢?通过API中搜索,查到Thread类。通过阅读Thread类中的描述。Thread是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。1.2 继续阅读,发现创建新执行线程有两种方法。1)一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。创建对象,开启线程。run方法相当于其他线程的main方法...

weixin_34952098的博客 356

基于python+flask框架的基于微信小程序的CR公司建设项目信息管理系统-前台(开题+程序+论文) 计算机毕设

特别是随着移动互联网技术的普及,企业对便捷、高效的信息管理系统的需求日益迫切。另一方面,该系统集成了仓管、物料、财务、人事、供应商等多个模块,实现了数据的集中管理和信息共享,有助于企业实现精细化管理,降低运营成本,提升决策效率。:深入调研CR公司的业务需求,明确系统应具备的功能模块,包括仓管员管理模块(物料信息、退回记录、申请信息、仓库信息管理)、财务员管理模块(资金信息管理、采购与租赁款项处理)、人事管理模块、供应商管理模块、项目管理模块(项目信息、设备采购、物料采购、设备租赁)、以及考勤打卡模块等。

zhihao503的博客 960

JAVA数据结构篇--13线程安全的Set 集合

线程安全的Set 集合

拽着尾巴的鱼儿的博客 9394

别再被坑了!手把手教你从官网下载免费正版Notepad++(附最新网盘链接)

本文详细指导如何从Notepad++官网安全下载正版软件,避免山寨版本带来的安全风险。通过识别官网特征、推荐官方下载渠道、揭露山寨网站骗局及验证正版功能,帮助用户高效获取纯净的Notepad++代码编辑器,并分享实用插件和配置优化技巧。

weixin_42527654的博客 566

基于LSTM的多变量温度预测(python从入门到入坑)

基于LSTM的多变量温度预测(python) ——我保证他能够运行,而且结果能够让你满意(如果你和我一样都是一个新手的话) 这里写目录标题基于LSTM的多变量温度预测(python)——我保证他能够运行,而且结果能够让你满意(如果你和我一样都是一个新手的话)一、我为什么要写这些?二、具体做了什么?三、源代码切块加注释,恳请批评指正(●’◡’●)ノ 一、我为什么要写这些? 因为让人抓狂的课程大作业,我小组选择了一个多变量预测方面的课题,在我这个大三基本上还没接触过Python数据处理,甚至对神经网络什么的都

代码之狐的博客 1万+

三、Thread 类和Runnable 接口详解

三、Thread 类和Runnable 接口详解

shiyu_951的博客 1782

一分钟理解 “熔断“, “限流“ 与 “降级“

熔断,本质是一种“故障隔离”机制,用于当某个依赖服务出现持续故障(如响应超时、错误率飙升)时,暂时切断对该服务的调用,避免故障扩散到整个系统,防止“雪崩效应”;待依赖服务恢复正常后,再逐步恢复调用。其核心逻辑参考了现实中的“电路保险丝”——电路过载时,保险丝熔断,切断电路,保护电器不被烧毁;故障排除后,更换保险丝,电路恢复正常。闭合状态(Closed):正常状态,请求可以正常调用依赖服务,同时监控调用的错误率、超时率等指标。打开状态(Open)

h a 6 6 6 c k 为 你解决复杂难题! 1484

多线程从入门到高级(6)--多线程环境下的集合安全类-Set

一、HashSet线程安全? HashSet的底层是HashMap,由前面的文章可以知道HashMap是线程不安全的,那么理所应当的HashSet也是线程不安全的,例如可看如下代码: public class HashSetDemo { public static void main(String[] args) { Set<Integer> set = new HashSet<>(); for (int i = 0; i < 30; i

Gopuwe的博客 1057

msfvenom制作windows/linux/android/ios木马

msfvenom选项如下 -p, --payload<payload> 指定 payload(攻击荷载)。如果使用自定义payload,请使用'-'或者stdin指定。 -l, --list [module_typel列出指定模块的所有可用资源。模块类型包括:payloads, encoders, nops, all -n, --nopsled <length>为payload预先指定一个NOP滑动长度。 -f, --format <format>指定输出格式(使

Cwillchris的博客 2735

【ArcGIS微课1000例】0066:图像融合(全色+多光谱)操作案例教程

图像融合是指将不同类型传感器的影像进行融合,既能使图向具有较高的空间分辨率,又具有多光谱的特性。除了遥感软件如Erdas能进行图像融合,ArcGIS软件也可以进行图像融合等图像增强操作。

智慧空间实验室 3078

Java 多线程并发编程(三) 并发容器类

分析容器类的时候,其实规律都是一样的,首先我们要找到容器类中真正存放数据的数据结构;接着通过容器类的添加元素和删除元素的方式来分析容器类的工作过程。接下来让我们开始今天的分析之路吧! 首先解释一下 CAS 操作:CAS 即 CompareAndSwap,也就是说先比较,再交换,那么比较什么?比较的是预期的变量值与实际的变量值是否一致,如果一致,那么就将变量的值与新值进行交换;如果不一致,则 CA...

championzgj的博客 258

面试真题集(十六):TensorRT基础

TensorRT面试真题解析:从模型优化到推理部署 本文精选了14道TensorRT面试题,涵盖选择题、简答题和场景题,深度考察推理工程师对TensorRT核心技术的理解。内容聚焦三个关键维度: 基础概念 FP16推理中Softmax层为何需保持FP32(数值稳定性) INT8校准原理(EntropyCalibrator2的鲁棒性优势) Plugin V3接口的构建/运行分离设计 性能优化 Conv-BN-ReLU融合减少40-60%延迟的关键机制(访存优化) 动态Shape配置策略(min/opt/max

PeterPan的博客 71

Java技术——Java多线程学习

0.前言 转载请标明出处:http://blog.youkuaiyun.com/seu_calvin/article/details/52400927 学习多线程之前需要先了解以下几个概念。 进程:一般指一个程序运行时的实例,每个进程有自己独立的地址空间。一个进程无法直接访问另一个进程的数据。 线程:是CPU调度的最小单元,一个进程可以有很多线程,每条线程可以并行执行不同的任务。并且每个线程有独立的运...

关于Android开发的一些技术点总结 ╮( ̄▽ ̄”)╭ 1万+

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Java 多线程详解

多线程(Multithreading)是指在一个程序中同时执行多个线程的能力。线程是进程中的一个执行路径,多线程允许程序在同一时间内执行多个操作。Java 中的多线程可以通过并发处理来提高程序的性能和响应速度,尤其在处理复杂计算、大量 I/O 操作或并发任务时非常有用。多线程使得程序可以同时执行多个任务,充分利用CPU资源,提升程序性能,增强响应性,并简化程序的复杂度。尽管多线程编程带来了一些挑战,如线程安全和死锁问题,但合理设计和使用多线程可以显著改善程序的整体表现。

goTsHgo的博客 2040

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【Java多线程】Java多线程技能

到 1. 进程和多线程的概念及线程的优点 提到多线程这个技术就不得不提及“进程”这个概念,在“百度百科”中对进程的解释如下: 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。 进程是受操作系统管理的基本运行单元。 那什么是线程呢? 线程可以理解成是在

一定要站在自己热爱的生活里闪闪发光 4万+

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

java多线程

在计算机中,我们把一个任务称为一个进程,浏览器就是一个进程,视频播放器是另一个进程,类似的,音乐播放器和Word都是进程。某些进程内部还需要同时执行多个子任务。例如,我们在使用Word时,Word可以让我们一边打字,一边进行拼写检查,同时还可以在后台进行打印,我们把子任务称为线程。进程和线程的关系就是:一个进程可以包含一个或多个线程,但至少会有一个线程。操作系统调度的最小任务单位其实不是进程,而是线程。

m0_60301012的博客 775

Java多线程

Java多进程,多线程编程,如何创建线程,线程启动中断等待,了解各种线程状态,线程安全以及如何解决线程安全问题,锁的作用,以及如何加锁,了解死锁怎么出现,如何解决死锁问题

Coding经历 1424

JAVA多线程是什么

一、 什么是多线程: 我们现在所使用操作系统都是多任务操作系统(早期使用的DOS操作系统为单任务操作系统),多任务操作指在同一时刻可以同时做多件事(可以同时执行多个程序)。 多进程:每个程序都是一个进程,在操作系统中可以同时执行多个程序,多进程的目的是为了有效的使用CPU资源,每开一个进程系统要为该进程分配相关的系统资源(内存资源) 多线程:线程是进程内部比进程更小的执行单元(执行流|程序片段),每个线程完成一个任务,每个进程内部包含了多个线程每个线程做自己的事情,在进程中的所有线程共享该进程的资源; 主

qq_45022104的博客 4446

java多线程是什么_Java多线程是什么

本篇文章将介绍一下多线程和其实例。Java编写程序都运行在在Java虚拟机(JVM)中,在JVM的内部,程序的多任务是通过线程来实现的。每用java命令启动一个java应用程 序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线 程来运行。一般常见的Java应用程序都是单线程的。比如,用java命令运行一个最简单的Hello...

weixin_33050129的博客 379

Java中多线程技术

最近由于工作的原因开始决定系统学习一下Java的多线程机制。Java语言的一大特点就是内在支持多线程,这和很多语言需要通过外部开发包来实现多线程有本质区别。每个程序都有一个主线程,当程序启动时自动执行。关于多线程的一些概念性东西,见这篇博文:多线程初步。

晓风残月xj 1421

JAVA 的多线程浅析

JAVA 的多线程浅析                                                                                  作者:马光晖一 JAVA 语言的来源、及特点在这个高速信息的时代,商家们纷纷把信息、产品做到Internet国际互连网页上。再这些不寻常网页的背后,要属功能齐全、安全可靠的编程语言,Java是当之无愧的

解惑 2514

java多线程应用_Java多线程的应用总结

多线程的好处:在java中通常每一个任务称为一个线程,但是多线程实现一个程序同时执行多个任务。直接了当的说多线程可以把任务分块执行,分块后可以同时进行而不用等待。 如下载文件,浏览网站时加载图片,通过多线程就可以实现多文件下载,一下做好几个工作,这样效率更高,线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实...

weixin_31081671的博客 774

[java多线程][java] java多线程拼接字符串

前言: 看到一个java多线程拼接字符串的题,所以就来写一下。 题目描述 Java多线程 时间限制:C/C++语言 1000MS;其他语言 3000MS 内存限制:C/C++语言 65536KB;其他语言 589824KB 题目描述: 设计三个线程,三个线程并行执行,要求分别在控制台输入数据后面拼接"_A","_B","_C",并且需要保证线程1,线程2,线程3按顺序执行,即线程1执行完成后,再执...

qq_39397165的博客 1370

java多线程原理_Java中多线程原理详解

Java是少数的集中支持多线程的语言之一,大多数的语言智能运行单独的一个程序块,无法同时运行不同的多个程序块,Java的多线程机制弥补了这个缺憾,它可以让不同的程序块一起运行,这样可以让程序运行更加顺畅,同时也达到了多任务处理的目的。一、线程和进程的概念现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。进程是程序的一个动态执行过程,是指一个内存中运行的应用程序,每个进程都有自己独立的一...

weixin_33241808的博客 1096
下一篇: JAVA IO
SetO2
博客等级 码龄12年 5粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值