01 线程的概念和创建.txt

UP 返回
视频:H:\视频教程\53套JAVA技术提升及架构精华课\41.第四十一套 Java并发编程原理与实战

1 可以在控制台通过jconsole命令查看java进程

  相关书籍:
	《Java并发编程实战》
	《Java并发编程的艺术》 方腾飞
	《深入理解Java虚拟机》  周志明

2 并发的缺点
	安全性问题
	活跃性问题(饥饿)
	性能问题
  多线程不一定是并发。因为即使只有一个cpu,也可以创建多线程,只不过这些线程并不是同时执行(但是线程切换的很快时,给人的感觉就是在并发)。真正的并发应该是多个线程同时进行,多个cpu就可以做到

  线程与进程的区别:
	进程:运行中的程序
	进程是资源分配的基本单位;进程中包含多个线程,线程共享进程的资源;线程是处理器调度的基本单位

  多线程不一定快,因为线程的切换也会浪费资源

  线程状态转换参Java/02.线程中的描述

  thread.setDaemon(true)			将线程设置为守护线程,这样线程会随着主线程的退出自动结束。这句话要写在start()之前。比如垃圾回收线程

  stop方法废弃的原因:因为这种方式只会让线程无限等待下去,并不会释放它的锁和静态资源。现在推荐使用interrupt方法来使线程中断,相应写法是:
		public static void main(String []args) {
			MyThread thread1=new MyThread("线程1");
			MyThread thread2=new MyThread("线程2");
			thread1.start();
			thread2.start();
			thread1.interrupt();										//中断线程
		}
		
		public MyThread(String name) {
			super(name);
		}
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(!interrupted()) {										//这里以后不要再使用while(true)来实现了,这种中断的方式更好
				System.out.println(getName()+" is running");
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

3 线程的创建
  继承Thread类
  实现Runnable接口
  匿名内部类的方式
	new Thread(){
	}.start();
	new Thread(new Runnable(){
		}
	).start();
	如果两个方法都使用,即同时重写了接口和类的run方法,最终调用的是类的run。因为作为子类,接口中的任务只是被父类指向了,而多态调用的仍然是子类的方法
  带返回值的线程
	使用方法:
		public class MyCallable implements Callable<Integer> {

			public static void main(String[] args) throws Exception {
				MyCallable myCallable = new MyCallable();
				FutureTask<Integer> task = new FutureTask<Integer>(myCallable);
				Thread t = new Thread(task);
				t.start();
				Integer result = task.get();
				System.out.println("结果为:" + result);
			}
		
			@Override
			public Integer call() throws Exception {
				// TODO Auto-generated method stub
				System.out.println("计算中...");
				return 1;
			}
		
		}
  定时器(quartz 定时任务框架)
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				// 实现定时任务
				System.out.println("timer is running");
			}
		}, 0, 1000);// 规定定时任务立刻执行,并每隔一秒执行一次(还有很多其他构造方法,可以自己尝试)
  线程池的实现
		ExecutorService threadPool = Executors.newFixedThreadPool(10);
		// ExecutorService threadPool = Executors.newCachedThreadPool();
		for (int i = 0; i < 10; i++) {
			threadPool.execute(new Runnable() {
				@Override
				public void run() {
					// TODO Auto-generated method stub
					System.out.println(Thread.currentThread().getName() + " is running");
				}
			});
		}
  Lambda表达式实现
		public class LambdaTest {
			public static void main(String[] args) {
				List<Integer> values = Arrays.asList(10, 20, 30, 40);
				int res = new LambdaTest().add(values);
				System.out.println(res);
			}
		
			public int add(List<Integer> values) {
				// parallelStream获取的流就是并行执行的
				values.parallelStream().forEach(System.out::println);
				// stream获取的流不是并行执行的。可以通过打印出的数字顺序看出来
				values.stream().forEach(System.out::println);
				// 如果并行还希望顺序是和开始一致的,可以使用forEachOrdered来遍历
				values.parallelStream().forEachOrdered(System.out::println);
		
				// 以上的代码只是为了验证parallelStream是并行的。下面这句才是实际的方法体
				return values.parallelStream().mapToInt(a -> a).sum();
			}
		}
  Spring实现多线程
	创建一个maven项目,引入context依赖(参 D:\ProjectCodes\eclipse2019\testPro)
	创建配置类Config
		@Configuration
		@ComponentScan("com.dm.test1")
		@EnableAsync
		public class Config {
		
		}
	创建异步类DemoService
		@Service
		public class DemoService {
		
			@Async
			public void method1() {
				while (true) {
					System.out.println("method1 run");
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		
			@Async
			public void method2() {
				while (true) {
					System.out.println("method2 run");
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
	创建运行类Run
		public class Run {
			public static void main(String[] args) {
				AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
				DemoService demoService = ac.getBean(DemoService.class);
				demoService.method1();
				demoService.method2();
			}
		}
	可以看到方法交替异步运行
		
4 多线程的风险
  4.1 活跃性问题
	死锁	哲学家问
	饥饿	低优先级长时间无法执行
		饥饿与公平:
			高优先级吞噬所有低优先级的CPU时间片
			线程被永久堵塞在一个等待进入同步块的状态
			等待的线程永远不被唤醒
		如何尽量避免饥饿问题
			设置合理的优先级
			使用锁来代替synchronized
	活锁	互相谦让,导致都无法执行 
  4.2 性能问题
  4.3 线程安全问题
	多线程环境下
	多个线程共享一个资源
	对资源进行非原子性操作



进入java项目目录,使用javap -verbose $XXXXX$1.class可以查看编译的字节码文件内容




























DOWN 返回