ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线程(一)

2022-01-28 20:01:23  阅读:82  来源: 互联网

标签:name Thread void 线程 new public


目录

1.生命周期(五种状态--创建、就绪、运行、阻塞、死亡)

1.1 创建线程

        1.1.1 继承Thread--实例

        1.1.2 实现Runnable接口--实例

        1.1.3 实现Callable接口--实例

1.2 阻塞线程

        1.2.1 join()

        1.2.2 yield()

2.三大特性

2.1 原子性

 2.2 有序性

2.3 可见性

3.CAS

4.生产者消费者模型

4.1 概念

4.2 代码实现

        4.2.1 创建实体类--Food

        4.2.2 生产者进程 及 消费者进程

        4.2.3 定义队列

        4.2.4 调用--Main

5.线程池

5.1 概念及其优势

5.2 创建线程池

        5.2.1 创建50个线程   Executors.newCachedThreadPool();

         5.2.2 单线程  Executors.newSingleThreadExecutor();

        5.2.3 定义几个即运行几个 Executors.newFixedThreadPool(n);

5.3 创建线程池并定时执行任务

6.死锁问题

实例:循环等待

7.synchronized和ReetreeLock区别

 实例:票务系统


1.生命周期(五种状态--创建、就绪、运行、阻塞、死亡)

1.1 创建线程

        1.1.1 继承Thread--实例

public class Thread01 extends Thread {
	private String name;//给线程名称
	
	public Thread01(String name) {
		this.name = name;
	}
	
	//线程运行
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(this.name+"--"+i);//拥有时间片资源--即运行
			try {
				//线程阻塞    
                //Thread01继承Thread,则拥有Thread的方法 可以直接调用方法
				sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		//实例化对象   创建
		Thread t1 = new Thread01("A");
		Thread t2 = new Thread01("B");
		Thread t3 = new Thread01("C");
		//就绪
		t1.start();
		t2.start();
		t3.start();
		//运行结束--线程死亡
	}
}

运行结果部分截图如下所示:

        1.1.2 实现Runnable接口--实例

public class Thread02 implements Runnable{
	private String name;//给线程名称
	
	public Thread02(String name) {
		this.name = name;
	}
	
	//线程运行
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(this.name+"--"+i);//拥有时间片资源--即运行
			try {
				//线程阻塞
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
//		//实例化对象   创建
//		Thread t1 = new Thread(new Thread02("A"));
//		Thread t2 = new Thread(new Thread02("B"));
//		Thread t3 = new Thread(new Thread02("C"));
//		//就绪
//		t1.run();
//		t2.run();
//		t3.run();
//		//运行结束--线程死亡
		
		/*lambda表达式*/
//		new Thread(()-> {
//			for(int i=1;i<=10;i++) {
//				System.out.println(Thread.currentThread().getName()+"-"+i);
//				try {
//					Thread.sleep(200);
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				}
//			}
//		}).start();;
		
		/** 匿名内部类 */
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 1; i <= 10; i++) {
					System.out.println(Thread.currentThread().getName()+"-"+i);
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}).start();;
	}
}

        1.1.3 实现Callable接口--实例

/**
 * Callable接口  : 有返回值    可抛出异常
 * @author 皮卡丘
 *
 */
public class Thread03 implements Callable {
	@Override
	public Object call() throws Exception {
		int s = 0;
		for (int i = 0; i < 1000; i++) {
			s += i;
		}
		return s;
	}

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<Integer> ft = new FutureTask<Integer>(new Thread03());
		ft.run();
		System.out.println("result: "+ft.get());
	}
}

1.2 阻塞线程

        1.2.1 join()

public class ThreadBlock extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
			System.out.println(this.getName()+"--"+i);
		}
		try {
			sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		Thread t1 = new ThreadBlock();
		Thread t2 = new ThreadBlock();
		Thread t3 = new ThreadBlock();
		//线程交叉执行
		t1.start();
		t1.join();//阻塞其他线程,先执行t1
		t2.start();
		t3.start();
	}
}

        1.2.2 yield()

public class ThreadBlock extends Thread {
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			//当前值为偶数,则让出时间片,让其他线程先运行
			if(i%2==0) {
				yield();
			}
			System.out.println(this.getName()+"--"+i);
			try {
				sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		Thread t1 = new ThreadBlock();
		t1.setName("V");
		Thread t2 = new ThreadBlock();
		t2.setName("A");
		Thread t3 = new ThreadBlock();
		t3.setName("L");
		
		t1.start();
		t2.start();
		t3.start();
		
	}
}

2.三大特性

2.1 原子性

        线程运行步骤不可分割  (例:i++ i-- ++y --y 均不是原子操作) 

        incrementAndGet 自增并获取值

        但是原子性操作基于CAS ,会出现ABA问题(先将A修改为B,在修改回A,此时CAS是无法察觉的)解决方法:版本号+1,在修改前在判断该值,未被修改则修改,否则重新取值进行修改。

public class ThreadAtomic extends Thread {
//	public static int x = 0;
	public static final AtomicInteger x = new AtomicInteger(0);
	
	public static class AtomicThread extends Thread{
		@Override
		public void run() {
			while(true) {
//				x++;
//				System.out.println(this.getName()+"--"+x);
				System.out.println(this.getName()+"--"+x.incrementAndGet());
				try {
					sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String[] args) {
		Thread t1 = new AtomicThread();
		t1.setName("A");
		Thread t2 = new AtomicThread();
		t2.setName("B");
		Thread t3 = new AtomicThread();
		t3.setName("C");
		
		t1.start();
		t2.start();
		t3.start();
		
	}
}

        非原子性的执行结果会出现重复,将运行步骤拆分,存在有的线程从第一步进行操作,而有的线程从第二步操作。(例如:x++;  拆分为y = x;   y = y +1;两步)

 2.2 有序性

        程序执行的顺序按照代码的先后顺序执行。在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

public class OrderThreadDemo {

	private  static volatile OrderThreadDemo instance = null;
	
	private OrderThreadDemo() {}
	
	
	public static OrderThreadDemo getInstance() {
		/**
		 * 两个线程进入方法
		 *   if   instance == null 
		 *   准备创建对象  instance = new OrderThreadDemo();
		 *   可能分为三个流程:
		 *     1. 开辟内存空间
		 *     2. 初始化对象
		 *     3. 引用和对象绑定
		 *     
		 *     另外一种方式:
		 *      1. 开辟内存空间
		 *      2. 引用和对象绑定   instance--->对象,instance不是null
		 *      3. 初始化对象(未完成)
		 */
		
		 if(instance==null) {//判断OrderThreadDemo对象是否存在
			 instance = new OrderThreadDemo();
		 }
		 
		 return instance;
	}

}

2.3 可见性

         使用volatile关键字(将修改的值立刻更新到主存中,对其他线程有作用  (共享)),即一个线程修改后,通知到所有线程
         线程运行将资源复制到工作内存中,在其中修改对其他线程不起作用

public class ThreadVisable extends Thread {
//	public static boolean f = false;
	public static volatile boolean f = false;
	
	public static class A extends Thread{
		@Override
		public void run() {
			while(true) {
				//当f为true时,打印语句
				if(f) {
					System.out.println(this.getName()+"--"+f);
					break;
				}
			}
		}
	}
	
	public static class B extends Thread{
		@Override
		public void run() {
			try {
				sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			f = true;
			System.out.println(this.getName()+"::"+f);
		}
	}
	
	public static void main(String[] args) {
		Thread t1 = new A();
		t1.setName("A");
		Thread t2 = new B();
		t2.setName("B");
		
		t1.start();
		t2.start();
	}
}

未使用关键字,则一个线程修改后对其他线程无影响-->体现不出可见性

3.CAS

  • 它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新的给定值。
  • 操作结果必须说明是否进行替换; 这可以通过一个简单的布尔响应(这个变体通常称为比较和设置),或通过返回从内存位置读取的值来完成。
  • 比较和交换 作为单个原子操作完成, 原子性保证新值基于最新信息计算; 如果该值在同一时间被另一个线程更新,则写入将失败。

         当多个线程同时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。失败的线程不会挂起,仅是被告知失败,并且允许再次尝试,当然也允许实现的线程放弃操作。 基于这样的原理,CAS 操作即使没有锁,也可以发现其他线程对当前线程的干扰。

4.生产者消费者模型

4.1 概念

         生产者和消费者的任务很明确,生产者只管生产数据,然后添加到缓冲队列。而消费者只管从缓冲队列中获取数据。

4.2 代码实现

        4.2.1 创建实体类--Food

public class Food{
	private String name;
	
	public Food(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Food [name=" + name + "]";
	}	
}

        4.2.2 生产者进程 及 消费者进程

public class ProducerThread extends Thread{
	private KFC kfc;

	public ProducerThread(KFC kfc) {
		this.kfc = kfc;
	}
	
	@Override
		public void run() {
			while(true) {
				kfc.produce();
				try {
					sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

			}
		}
}
public class ConsumerThread extends Thread {
	private KFC kfc;

	public ConsumerThread(KFC kfc) {
		this.kfc = kfc;
	}
	
	@Override
		public void run() {
			while(true) {
				kfc.consume();
				try {
					sleep(400);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
}

        4.2.3 定义队列

public class KFC {
	//定义缓存事物队列
	private Deque<Food> q = new LinkedList<Food>();
	private final int MAX_SIZE = 10;
	
	/**
	 * 生产食物
	 */
	public synchronized void produce() {
		while(q.size()==MAX_SIZE) {
			try {
				System.out.println("队列已满,生产者休息等待消费者消费");
				wait();//阻塞进程     wait()会释放锁,要将方法变为同步方法(加suo)
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		Food food = new Food("鸡肉饼");
		q.offer(food);
		System.out.println("生产者生产一个"+food+",还有食物"+q.size());
		notify();//欢迎其他的进程
	}
	
	/**
	 * 消费食物
	 */
	public synchronized void consume() {
		while(q.isEmpty()) {//队列为空 消费者不能消费
			System.out.println("队列为空,消费者休息,等待生产者生产......");
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		Food food = q.poll();
		System.out.println("消费者,消费一个:"+food+",还有食物"+q.size());
		notifyAll();
	}	
}

        4.2.4 调用--Main

public class Main {
	public static void main(String[] args) {
		KFC kfc = new KFC();
		
		Thread p1 = new ProducerThread(kfc);
		Thread p2 = new ProducerThread(kfc);
		Thread p3 = new ProducerThread(kfc);
		
		Thread c1 = new ConsumerThread(kfc);
		Thread c2 = new ConsumerThread(kfc);
		Thread c3 = new ConsumerThread(kfc);
		Thread c4 = new ConsumerThread(kfc);
		Thread c5 = new ConsumerThread(kfc);
		
		p1.start();
		p2.start();
		p3.start();
		
		c1.start();
		c2.start();
		c3.start();
		c4.start();
		c5.start();
	}
}

运行结果:

5.线程池

5.1 概念及其优势

        线程池:一个线程执行结束后不马上销毁,继续执行新的任务,这样就节省了不断创建线程和销毁线程的开销。

        优势:

  • 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
  • 提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执
  • 行;
  • 方便线程并发数的管控。
  • 提供更强大的功能,延时定时线程池

5.2 创建线程池

        5.2.1 创建50个线程   Executors.newCachedThreadPool();

public class poolDemo {
	public static void main(String[] args) {
		int count = 0;
		//创建50个线程   10*5
		Executor pool = Executors.newCachedThreadPool();
		while(count++ < 10) {
			pool.execute(()->{
				for(int i=0;i<5;i++) {
					System.out.println(Thread.currentThread().getName()+"::"+i);
				}
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			});
		}
	}
}

         5.2.2 单线程  Executors.newSingleThreadExecutor();

public class poolDemo {
	public static void main(String[] args) {
		int count = 0;
		//单线程运行--一个线程循环执行
		Executor pool = Executors.newSingleThreadExecutor();
		while(count++ < 10) {
			pool.execute(()->{
				for(int i=0;i<5;i++) {
					System.out.println(Thread.currentThread().getName()+"::"+i);
				}
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			});
		}
	}
}

        5.2.3 定义几个即运行几个 Executors.newFixedThreadPool(n);

public class poolDemo {
	public static void main(String[] args) {
		int count = 0;
		//定义几个线程就是几个线程在跑
		Executor pool = Executors.newFixedThreadPool(2);
		while(count++ < 10) {
			pool.execute(()->{
				for(int i=0;i<5;i++) {
					System.out.println(Thread.currentThread().getName()+"::"+i);
				}
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			});
		}
	}
}

5.3 创建线程池并定时执行任务

public class poolDemo {
	public static void main(String[] args) {
		ScheduledExecutorService es = Executors.newScheduledThreadPool(3);
		//es.scheduleAtFixedRate(command, 延迟时间, 间隔时间, 事件类型);
		es.scheduleAtFixedRate(()->{System.out.println("当前时间:"+new Date());}, 0, 1, TimeUnit.SECONDS);
	}
}

6.死锁问题

实例:循环等待

public class Resource {
	private String name;
	
	public Resource(String name) {
		this.name=name;
	}

	@Override
	public String toString() {
		return "Resource [name=" + name + "]";
	}	
}
public class DeadLock implements Runnable {
	Resource a = new Resource("A");
	Resource b = new Resource("B");

	public DeadLock(Resource a,Resource b) {
		this.a = a;
		this.b = b;
	}
	
	@Override
	public void run() {
		System.out.println("准备锁资源:"+a+"......");
		synchronized (a) {
			System.out.println("资源:"+a+"锁定成功");
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("准备锁资源:"+b+"......");
			synchronized (b) {
				System.out.println("资源:"+b+"锁定成功");
			}
			System.out.println("资源"+b+"释放成功");
		}
		System.out.println("资源"+a+"释放成功");
	}
}
public class DeadLockTest {
	public static void main(String[] args) {
		Resource a = new Resource("A");
		Resource b = new Resource("B");
		Resource c = new Resource("C");
		
		//线程实现ruannable 定义对象的方法
		Thread t1 = new Thread(new DeadLock(a, b));
		Thread t2 = new Thread(new DeadLock(b, c));
		Thread t3 = new Thread(new DeadLock(c, a));
		
		t1.start();
		t2.start();
		t3.start();
	}
}

 执行结果如下所示:

7.synchronized和ReetreeLock区别

synchronizedReetrantLock
不需要手动释放锁和开启锁使用灵活,但必须有释放锁动作
对象之间是互斥关系手动释放和开启锁
只适用于代码块锁

 实例:票务系统

public class Ticket {
	private int num = 100;
	private static final ReentrantLock lock = new ReentrantLock();//可重入锁   使用灵活  手动关锁,避免死锁
	
	//卖票
	public void sold(String name) {
		lock.lock();
		try {
			int s = --num;
			System.out.println(name+",卖出一张票,剩余票数:"+s);
		} finally{
			lock.unlock();
		}
	}
	//获取剩余票数
	public int getNum() {
		return num;
	}
}
public class TicketThread extends Thread{
	private Ticket ticket;
	private String name;
	
	public TicketThread(Ticket ticket,String name) {
		this.ticket = ticket;
		this.name = name;
	}
	
	@Override
	public void run() {
		while(ticket.getNum()>0) {
			ticket.sold(name);
			try {
				sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
public class TicketTest {
	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		
		TicketThread t1 = new TicketThread(ticket, "A");
		TicketThread t2 = new TicketThread(ticket, "B");
		TicketThread t3 = new TicketThread(ticket, "C");
		
		t1.start();
		t2.start();
		t3.start();
	}
}

 执行结果如下图所示:

 

标签:name,Thread,void,线程,new,public
来源: https://blog.csdn.net/weixin_59758304/article/details/122731310

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有