进程:针对操作系统,一个系统多个任务进程。比如开一个视频播放,开一个QQ
线程:是进程中的运行单元。
多线程:一个项目或应用可以分多个线程并行执行,由CPU分配时间片进行调用。
线程的状态
1.新建状态 new Thread()
2.就绪状态 start()
3.运行状态 run
4.阻塞状态 失去CPU的时间片
5.线程终止 线程中的方法执行完毕
创建线程的方式
1.继承Thread 重写run方法,缺点单继承,不能再继承其他类
2.实现Runnable接口(静态代理 Thread代理角色)好处:可以继承或实现其他接口
3.实现Callable接口 优点:可以返回值,可以抛出自定义异常
合并线程,插队
join()
/** * 线程阻塞 * @author Administrator * */ public class ZuseThread extends Thread{ public void run() { for (int i = 0; i < 500; i++) { System.out.println("ZuseThread-->"+i); } } public static void main(String[] args) throws InterruptedException { ZuseThread zuseThread = new ZuseThread(); zuseThread.start(); for (int i = 0; i < 500; i++) { if(i==50){ //当mian线程执行到i=50的时候mian线程阻塞开始执行ZuseThread线程,执行完后再执行mian线程
//Thread.yield();静态方法,暂停当前线程mian,让出时间片
zuseThread.join(); } System.out.println("main-->"+i); } } }
暂停线程
yield() 静态方法,暂停下一,不是绝对的,接下是还否暂停取决于CPU
sleep() 静态方法,不释放锁,一般用于模拟延迟,倒计时
多线程并发执行,JAVA能保证每个线程都执行,不能保证执行顺序
线程优先级:1-10 优先级越高获得CPU的时间片的机会越多,不是绝对的
setPriority(1)
并发
多个线程访问一个资源,要确保资源的安全,需要加同步
1.同步块 synchronized (对象引用){
}
2.同步方法 public synchronized void aaa(){}
public class TT implements Runnable { public Integer b = 1000; public void m1() throws InterruptedException { synchronized(this.b){ this.b = 20000; Thread.sleep(5000); System.out.println(b); } } public synchronized void m3() throws InterruptedException { this.b = 20000; Thread.sleep(5000); System.out.println(b); } public void m2(){ System.out.println(b); } @Override public void run() { try { m1(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String []args) throws InterruptedException { TT tt = new TT(); Thread t1 = new Thread(tt); t1.start(); System.out.println("开始"); Thread.sleep(1000); tt.m2(); } }
线程不安全
public class Qiangpiao implements Runnable{ private int num = 50; @Override public void run() { while(true){ if(num<=0){ break; } try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢票"+num); num--; } } public static void main(String[] args) { Qiangpiao qiangpiao = new Qiangpiao(); Thread t1 = new Thread(qiangpiao, "甲"); Thread t2 = new Thread(qiangpiao, "乙"); Thread t3 = new Thread(qiangpiao, "丙"); t1.start(); t2.start(); t3.start(); } }
同步关键字
public class Qiangpiao implements Runnable{ private int num = 50; private boolean flag = true; public synchronized void tongbu(){ if(num<=0){ flag = false; return; } /*try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }*/ System.out.println(Thread.currentThread().getName()+"抢票"+num); num--; } @Override public void run() { while(flag){ tongbu(); } } public static void main(String[] args) { Qiangpiao qiangpiao = new Qiangpiao(); Thread t1 = new Thread(qiangpiao, "甲"); Thread t2 = new Thread(qiangpiao, "乙"); Thread t3 = new Thread(qiangpiao, "丙"); t1.start(); t2.start(); t3.start(); } }
死锁
/** * 线程死锁,有同步才会有死锁 * @author Administrator * */ public class Sisuo { public static void main(String[] args) { Object money = new Object(); Object goods = new Object(); Thread1 thread1 = new Thread1(money, goods); Thread t1 = new Thread(thread1); Thread2 thread2 = new Thread2(money, goods); Thread t2 = new Thread(thread2); t1.start(); t2.start(); } } class Thread1 implements Runnable{ Object money; Object goods; public Thread1(Object money, Object goods) { super(); this.money = money; this.goods = goods; } @Override public void run() { while(true){ synchronized (money) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (goods) { } } System.out.println("一手给钱"); } } } class Thread2 implements Runnable{ Object money; Object goods; public Thread2(Object money, Object goods) { super(); this.money = money; this.goods = goods; } @Override public void run() { while(true){ synchronized (goods) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (money) { } } System.out.println("一手给货"); } } }
解决并发可能出现的死锁:生产者消费者模式
/** * 生产者消费者 * @author Administrator * */ public class TestShengchanzhe { public static void main(String[] args) { Movie m = new Movie(); Player player = new Player(m); Watch watch = new Watch(m); new Thread(player).start(); new Thread(watch).start(); } } class Movie{ private String pic; //true 生产者生产,消费者等待,生产完成后通知消费 //false 消费者消费,生产者等待,消费完成后通知生产 private boolean flag = true; public synchronized void play(String pic) throws InterruptedException{ if(!flag){ this.wait();//会释放锁 } Thread.sleep(500); this.pic = pic; this.notify();//通知消费 this.flag = false; System.out.println("生产者生产-->"+pic); } public synchronized void watch() throws InterruptedException{ if(flag){ this.wait(); } Thread.sleep(200); this.notify(); this.flag = true; System.out.println("消费者消费-->"+pic); } } class Player implements Runnable{ Movie m; public Player(Movie m) { super(); this.m = m; } @Override public void run() { while(true){ try { m.play("馒头"); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Watch implements Runnable{ Movie m; public Watch(Movie m) { super(); this.m = m; } @Override public void run() { while(true){ try { m.watch(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
当一个进程有 500 个线程在跑的话,那性能已经是很低很低了。Tomcat 默认配置的最大请求数是 150,也就是说同时支持 150 个并发,当然了,也可以将其改大。
当某个应用拥有 250 个以上并发的时候,应考虑应用服务器的集群。
具体能承载多少并发,需要看硬件的配置,CPU 越多性能越高,分配给 JVM 的内存越多性能也就越高,但也会加重 GC 的负担。
操作系统对于进程中的线程数有一定的限制:
Windows 每个进程中的线程数不允许超过 2000
Linux 每个进程中的线程数不允许超过 1000
另外,在 Java 中每开启一个线程需要耗用 1MB 的 JVM 内存空间用于作为线程栈之用。
Tomcat的最大并发数是可以配置的,实际运用中,最大并发数与硬件性能和CPU数量都有很大关系的。更好的硬件,更多的处理器都会使Tomcat支持更多的并发。
Tomcat 默认的 HTTP 实现是采用阻塞式的 Socket 通信,每个请求都需要创建一个线程处理。这种模式下的并发量受到线程数的限制,但对于 Tomcat 来说几乎没有 BUG 存在了。
Tomcat 还可以配置 NIO 方式的 Socket 通信,在性能上高于阻塞式的,每个请求也不需要创建一个线程进行处理,并发能力比前者高。但没有阻塞式的成熟。
这个并发能力还与应用的逻辑密切相关,如果逻辑很复杂需要大量的计算,那并发能力势必会下降。如果每个请求都含有很多的数据库操作,那么对于数据库的性能也是非常高的。
对于单台数据库服务器来说,允许客户端的连接数量是有限制的。
并发能力问题涉及整个系统架构和业务逻辑。
系统环境不同,Tomcat版本不同、JDK版本不同、以及修改的设定参数不同。并发量的差异还是满大的。
maxThreads="1000" 最大并发数
minSpareThreads="100"///初始化时创建的线程数
maxSpareThreads="500"///一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。
acceptCount="700"// 指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理