1.创建线程的方式
1.1继承Thread类并重写run方法
publicclassThreadDemo1{publicstaticvoidmain(String[] args){
MyThread1 t1=newMyThread1();
MyThread2 t2=newMyThread2();/*
* 启动线程要调用start方法,而不是run方法
*/
t1.start();
t2.start();}}/**
* 第一种创建线程的方式的优点是定义简单,适合匿名内部类形式吃创建。
* 缺点主要有两个:
* 1:java是单继承的,这导致继承了Thread就无法再继承其他类去复用方法了,这在实际开发时很不方便。
* 2:将任务定义在线程中,会导致线程和任务存在必然的耦合关系,不利于线程的重用
* @author 张庆裕
*
*/classMyThread1extendsThread{publicvoidrun(){for(int i=0;i<100;i++){
System.out.println("你是谁");}}}classMyThread2extendsThread{publicvoidrun(){for(int i=0;i<100;i++){
System.out.println("我是张三");}}}
1.2实现Runnable接口单独定义线程任务
publicclassThreadDemo2{publicstaticvoidmain(String[] args){//创建任务
Runnable r1=newMyRunnable1();
Runnable r2=newMyRunnable2();//创建线程
Thread t1=newThread(r1);
Thread t2=newThread(r2);
t1.start();
t2.start();}}classMyRunnable1implementsRunnable{publicvoidrun(){for(int i=0; i<1000; i++){
System.out.println("你是谁");}}}classMyRunnable2implementsRunnable{publicvoidrun(){for(int i=0; i<1000; i++){
System.out.println("我是张三!");}}}
1.3使用匿名内部类形式创建线程
publicclassThreadDemo3{publicstaticvoidmain(String[] args){
Thread t1=newThread(){;publicvoidrun(){for(int i=0; i<1000; i++){
System.out.println("你是谁");}}};
Runnable r2=()->{for(int i=0; i<1000; i++){
System.out.println("我是张三!");}};
Thread t2=newThread(r2);
t1.start();
t2.start();}}
2.线程的优先级
/**
* 线程的优先级
*
* 线程获取CPU的时间片并发运行时,一切听从线程调度,线程是不能主动索取时间片的
* 只能被动被分配。
* 调整线程的优先级可以最大限度的干涉分配时间片的概率,原则上优先级越高的线程获取CPU时间片的次数越多。
* @author 张庆裕
*
*/publicclassPriorityDemo{publicstaticvoidmain(String[] args){
Thread max=newThread(){publicvoidrun(){for(int i=0;i<10000;i++){
System.out.println("max");}}};
Thread norm=newThread(){publicvoidrun(){for(int i=0;i<10000;i++){
System.out.println("nor");}}};
Thread min=newThread(){publicvoidrun(){for(int i=0;i<10000;i++){
System.out.println("min");}}};//线程优先级1最低,5默认,10最高
max.setPriority(Thread.MAX_PRIORITY);
norm.setPriority(Thread.NORM_PRIORITY);
min.setPriority(Thread.MIN_PRIORITY);
max.start();
norm.start();
min.start();}}
3.线程阻塞
3.1 Thread.Sleep(long ms)
/**
* static void Sleep(long ms)
* Thread提供的静态方法sleep可以让运行该方法的线程阻塞指定毫秒,超时后线程会自动
* 回到RUNNABLE状态,等待再次获取时间片并发运行。
* @author 张庆裕
*
*/publicclassSleepDemo{publicstaticvoidmain(String[] args){
System.out.println("程序开始了");/*
*实现一个倒计时程序,程序启动后要求输入一个整数,然后每秒递减,到0时输出时间到
*/
Scanner scan=newScanner(System.in);
System.out.println("请输入一个整数:");int num= scan.nextInt();while(num>0){try{
System.out.println(num--);
Thread.sleep(1000);}catch(InterruptedException e){// TODO Auto-generated catch block
e.printStackTrace();}}
System.out.println("时间到!");
System.out.println("程序结束了");}}
3.2 interrupt()方法中断其sleep阻塞
/**
* sleep方法要求我们必须处理InterruptedException,当一个线程调用sleep方法处于
* 阻塞的过程中,此时该线程的interrupt()方法被调用时会中断其sleep阻塞,此时该方法就会抛出这个异常
* @author 张庆裕
*
*/publicclassSleepDemo2{publicstaticvoidmain(String[] args){
Thread lin=newThread(){publicvoidrun(){
System.out.println("林:我要睡觉了,别吵我!");try{
Thread.sleep(100000);}catch(InterruptedException e){
System.out.println("林:干嘛嘞,干嘛嘞!");}
System.out.println("林:我醒了");}};
Thread huang=newThread(){publicvoidrun(){
System.out.println("黄:开始砸墙!");for(int i=0;i<5;i++){
System.out.println("黄:80!");try{
Thread.sleep(1000);}catch(InterruptedException e){}}
System.out.println("黄:搞定了");
lin.interrupt();}};
lin.start();
huang.start();}}
4.线程的相关方法
publicclassThreadInfoDemo{publicstaticvoidmain(String[] args){
Thread t= Thread.currentThread();
String name= t.getName();
System.out.println("线程名字:"+name);long id= t.getId();
System.out.println("唯一标识:"+id);int priority= t.getPriority();
System.out.println("优先级:"+priority);//查看当前线程是否还活着boolean isAlive= t.isAlive();
System.out.println("isAlive:"+isAlive);//查看线程是否为守护线程boolean isDaemon= t.isDaemon();
System.out.println("isDaemon:"+isDaemon);//查看线程是否被中断了boolean isInterrupted= t.isInterrupted();
System.out.println("isInterrupted:"+isInterrupted);}}
5.守护线程
/**
* 守护线程
* 守护线程是通过普通线程调用setDaemon方法设置而来的,因此创建和使用其实与普通
* 线程无异。但是结束时机上有一点不同,即进程的结束
*
* 进程结束:当进程中的所有普通线程都结束时,进程就会结束,此时所有正在运行的守护线程都会被强制中断
* @author 张庆裕
*
*/publicclassDaemonThreadDemo{publicstaticvoidmain(String[] args){
Thread t1=newMyCommon();
Thread t2=newThread(newMyDaemon());
t1.start();
t2.setDaemon(true);//设置为守护线程,必须在该线程启动前进行!
t2.start();}}classMyCommonextendsThread{publicvoidrun(){for(int i=0; i<5; i++){
System.out.println(Thread.currentThread().getName()+"线程1第"+ i+"次执行!");try{
Thread.sleep(7);}catch(InterruptedException e){
e.printStackTrace();}}}}classMyDaemonimplementsRunnable{publicvoidrun(){while(true){
System.out.println(Thread.currentThread().getName()+"后台线程第次执行!");try{
Thread.sleep(7);}catch(InterruptedException e){
e.printStackTrace();}}}}
6.线程池
/**
* 线程池
* 线程池是管理线程的一套解决方案,主要工作:
* 1:控制线程数量
* 线程数量过多会消耗大量内存,有可能引起内存溢出崩溃,并且线程数量过多会导致CPU的过度切换,从而降低整体并发性能。
* 2:重用线程
* 线程不应当与任务的生命周期一致,重复使用线程可以减少线程调度器的不必要开销。
* @author 张庆裕
*
*/publicclassThreadPoolDemo{publicstaticvoidmain(String[] args){
ExecutorService threadPool= Executors.newFixedThreadPool(2);for(int i=0;i<5;i++){
Runnable r=newRunnable(){publicvoidrun(){try{
Thread t= Thread.currentThread();
System.out.println(t.getName()+":正在执行任务...");
Thread.sleep(5000);
System.out.println(t.getName()+":执行任务完毕!");}catch(Exception e){}}};
threadPool.execute(r);//将任务交给线程池
System.out.println("指派了一个任务给线程池...");}//threadPool.shutdownNow();//调用该方法线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;
System.out.println("停止线程池");}}
7.多线程并发安全问题
7.1.同步方法(synchronized)
/**
* 多线程并发安全问题
* 当多个线程并发操作同一临界资源时,由于线程切换的时机不确定,导致操作过程的顺序错乱,出现严重的后果
* 临界资源:同时只能被单个线程操作的资源。
* @author 张庆裕
*
*/publicclassSyncDemo1{publicstaticvoidmain(String[] args){
Table beans=newTable();
Thread t1=newThread(){publicvoidrun(){while(true){int bean= beans.getBean();
Thread.yield();
System.out.println(getName()+":"+bean);}}};
Thread t2=newThread(){publicvoidrun(){while(true){int bean= beans.getBean();
Thread.yield();
System.out.println(getName()+":"+bean);}}};
t1.start();
t2.start();}}classTable{privateint beans=20;/**
* 当一个方法被synchronized修饰后,该方法称为同步方法,即:多个线程不能同时在方法
* 内部执行,将异步调用方法该为同步调用可以解决并发安全问题
* @return
*/publicsynchronizedintgetBean(){if(beans==0){thrownewRuntimeException("没有豆子了!");}
Thread.yield();//使当前线程由执行状态,变成为就绪状态,让出cpu时间,在下一个线程执行时候,此线程有可能被执行,也有可能没有被执行return beans--;}}
7.2同步块
/**
* 同步块:
* 语法:
* synchronized(同步监视器对象){
* 需要多线程同步运行的代码片段
* }
*
* 同步块可以更准确的锁定需要同步运行的代码片段,有效的缩小同步范围可以在保证并发
* 安全的前提下提高并发效率
* @author 张庆裕
*
*/publicclassSyncDemo2{publicstaticvoidmain(String[] args){
Shop shop=newShop();
Thread t1=newThread(){publicvoidrun(){
shop.buy();}};
Thread t2=newThread(){publicvoidrun(){
shop.buy();}};
t1.start();
t2.start();}}classShop{//public synchronized void buy() {//没有任何同步约束时性能最好,但是存在并发安全问题/*
* 在方法上使用synchronized,那么指定的同步对象监视器对象就是this
*/publicvoidbuy(){//解决了并发安全问题 ,但是性能不好,原因是衣服可同时挑,试衣同一时间只能一个人试衣服try{
Thread t= Thread.currentThread();
System.out.println(t.getName()+":正在挑衣服!");
Thread.sleep(5000);