Java基础之多线程

多线程:

         JVM:Java虚拟机识别main(主线程);
                特点:
                        1> jvm是多线程的;
                        2> 有主线程,main..执行这些代码,能够被Jvm识别;
                        3> 在执行一些程序的时候,一些对象Jvm释放掉;
                                原因:它开启了垃圾回收线程,里面GC垃圾回收器(回收一些没有更多引用的对象或者变量...);
        几个思想:

                线程:用户在听歌的同时,可以使用QQ等操作,这些活动完全可以同时进行,这种思想在Java中成为并发,而将并发完成的每一件事情称为线程;

                多线程:Java语言中提供了并发机制,程序员可以在程序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机制称为多线程。在单线程中,程序代码按调用顺序依次往下,如果需要一个进程同时完成多段代码的操作,就需要产生多线程;

                进程:一个线程则是进程中的执行流程,一个进程中可以同时包括多个线程,每个线程也可以得到一小段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。


实现多线程的三种方式:

        1> 继承Thread类;
                注意:
                        run():只是调用了一个普通方法,并没有启动另一个线程,程序还是会按照顺序执行相应的代码;
                        start():则表示,重新开启一个线程,执行相应的run()方法,start()不能重复调用;
                举例:
package org.westos_04;
/**
 * 
 *MyThread类就是一个执行线程类
 *并且重写Thread类中的run 方法
 *	run()方法里面应该是一些耗时的操作,IO操作/循环语句..
 */
class MyThread extends Thread {

	@Override
	public void run() {
		//System.out.println("helloworld");
		for(int x = 0 ;x <5; x ++) { //两个线程都需要执行这个代码
			System.out.println(x);
		}
	}
}
public class ThreadDemo {

        public static void main(String[] args) {

                //创建MyThread类对象
                MyThread my = new MyThread() ;
                //当前Thread类有一个run public void run() 
                //执行线程不是run方法 ,run方法的调用相当于一个普通方法的调用
                my.run(); 

                /*public void start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 
                结果是两个线程并发地运行*/

                MyThread t1 = new MyThread() ;
                t1.start();
                //IllegalThreadStateException:非法状态异常,同一个线程只能被执行一次
                //t1.start();
                MyThread t2 = new MyThread() ;
                t2.start();

        }
}
         Thread类提供了一些方法:
                public final void setName(String name):给线程起名称;

                public final String getName():获取线程名称;
                public static Thread currentThread():返回当前正在执行的线程对象的引用;

        举例:

import java.security.AccessControlContext;
import java.security.AccessController;

class MyThread extends Thread {
	public MyThread() {
		
	}
	
	public MyThread(String name) {
		super(name) ;
	}

	@Override
	public void run() {
		
		for(int x = 0 ;x < 100 ; x++) {//t1,t2
			System.out.println(getName()+":"+x); //thread-线程编号(从0开始)
		}
	}
}
public class ThreadDemo {
	
	public static void main(String[] args) {
		
		//public Thread(String name):有参构造的形式
		MyThread t1 = new MyThread("张三") ;
		MyThread t2 = new MyThread("李四") ;
		t1.start();
		t2.start();
		
		//Thread类中提供另一个功能:
		//public static Thread currentThread():返回当前正在执行的线程对象的引用 ==> ,返回:当前执行的线程
		System.out.println(Thread.currentThread().getName());  //main
	}
}

        public final void join():等待该线程终止 interruputedException 中断异常;
                分别创建三个子线程,让第一个子线程执行之后,调用join()等待该线程中,在执行t2,t3线程;
        举例:

class ThreadJoin extends Thread {
	
	@Override
	public void run() {
		for(int x = 0  ; x < 100 ; x ++) {
			System.out.println(getName()+":"+x);
		}
	}
}

public class ThreadJoinDemo {
	
	public static void main(String[] args) {
		
		//创建三个子线程
		ThreadJoin t1 = new ThreadJoin() ;
		ThreadJoin t2 = new ThreadJoin() ;
		ThreadJoin t3 = new ThreadJoin() ;
		
		//分别给线程设置名称
		t1.setName("李渊");
		t2.setName("李世明");
		t3.setName("李元霸");
		
		t1.start();

                //如果中断了这个线程,那么久抛出这个异常
                //谁设置了join这个方法,那么谁就必须要执行完毕,再去执行别的线程
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

                //等到t1执行完后,t2和t3猜抢占CPU执行权
		t2.start();
		t3.start();
		
		
	}
}
        public static void yield():暂停当前正在执行的线程对象,并执行其他线程;
         举例:
class ThreadYield extends Thread {

	@Override
	public void run() {//t1,t2子线程线程都要执行这个run()方法
		for(int x = 0 ;x <100 ; x ++) {

			System.out.println(getName()+":"+x);//
			
		}
                //每一个线程都要调用yield()方法;
                //当ty1进来打印一个0,之后ty1等待,执行ty2,因为CPU的一点时间片段要执行很多次,
                //之后ty2调用yield()方法,ty1在执行一个时间片段,在调用yield()方法,一直到程序结束;
		Thread.yield();

	}
}
public class ThreadyieldDemo {
	
	public static void main(String[] args) {
		
		//创建两个子线程对象
		ThreadYield ty1 = new ThreadYield() ;
		ThreadYield ty2 = new ThreadYield() ;
		
		ty1.setName("张三");
		ty2.setName("李四");
		
		//分别启动线程
		ty1.start();
		ty2.start();
	}
}

        public final void setDaemon(boolean on):true时,表示为守护线程;
                将该线程标记为守护线程或用户线程;
                当正在运行的线程都是守护线程时,Java 虚拟机退出(守护线程不会立即结束掉,它会执行一段时间再结束掉);
                 条件:该方法必须在启动线程前调用;

        举例:
//可执行线程
class ThreadDaemon extends Thread {
	
	@Override
	public void run() {
		for(int x = 0 ; x<100; x ++) {
			System.out.println(getName()+":"+x);
		}
	}
}

public class ThreadDaemonDemo {
	
	public static void main(String[] args) {
		
		//创建两个子线程
		ThreadDaemon td1 = new ThreadDaemon() ;
		ThreadDaemon td2 = new ThreadDaemon() ;
		
		td1.setName("张飞");
		td2.setName("关羽");
		
		//在启动之前,设置为守护线程
		td1.setDaemon(true); 
		td2.setDaemon(true);
		
		td1.start();
		td2.start(); 

                //因为td1和td2是守护线程,那么在名为"刘备"的这个线程执行完后,程序不会停止,还会将td1和td2执行一段时间
		Thread.currentThread().setName("刘备");
		for(int x =0 ; x < 5 ; x ++) {
			System.out.println(Thread.currentThread().getName()+":"+x);
		}
	}
}
         跟线程优先级相关的方法:
  public final int getPriority():返回线程的优先级;
  public final void setPriority(int newPriority):更改线程的优先级;
  线程存在一个默认优先级;
                public static final int MAX_PRIORITY        10  最大优先级
                public static final int MIN_PRIORITY          1  最小优先级

                public static final int NORM_PRIORITY      5  默认优先级

        举例:

class MyThread extends Thread {
	
	@Override
	public void run() {
		for(int x = 0 ; x <100 ; x ++) {
			System.out.println(getName()+":"+x);
		}	
	}
}

public class ThreadDemo {

	public static void main(String[] args) {
		
		//创建三个子线程
		MyThread t1 = new MyThread() ;
		MyThread t2 = new MyThread() ;
		MyThread t3 = new MyThread() ;
		
		System.out.println(t1.getPriority()); //5 默认优先级
		System.out.println(t2.getPriority());
		System.out.println(t3.getPriority());
		
		t1.setName("林青霞");
		t2.setName("林志颖");
		t3.setName("林彪");
		
		//设置线程优先级
		t1.setPriority(10);    //抢占CPU执行权的几率最大
		t2.setPriority(1);
		t3.setPriority(5);
		
		t1.start();
		t2.start(); 
		t3.start();
	}
}
        public static void sleep(long millis):线程睡眠指定是时间毫秒值;

                throws InterruptedException:抛出一个异常;

        解释:t1和t2两个线程抢占CPU执行权,加入t1先抢到,开始执行,但是在这个过程中,t2来了,之后t1执行睡眠,之后t2执行,执行了一会t1醒了,t1和t2继续抢占CPU执行权,谁抢到谁执行,执行完睡眠,另一个接着执行;

        举例:

import java.util.Date;

class ThreadSleep extends Thread {

                @Override
                public void run() {
                for(int x = 0 ; x <100 ; x ++) {
                //t1,t2
                //t1, 0,1    //t2来了,之后t1执行睡眠,t2执行,3,4,5,6,7,8	//t2执行到8,t1醒了,接着执行2 ,,,
                System.out.println(getName()+":"+x+",日期是:"+new Date());

                //困了,想睡一秒钟
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
            }
        }
    }
}

public class ThreadSleepDemo {
	
	public static void main(String[] args) {
		
		//创建两个子线程
		ThreadSleep ts1 = new ThreadSleep() ;
		ThreadSleep ts2 = new ThreadSleep() ;
		
		ts1.setName("张三");
		ts2.setName("李四");
		
		ts1.start();
		ts2.start();
	}
}
        面试题:
                 stop()和interrupt()的区别:
                        public final void stop():强迫线程停止执行,不会执行了 (过时了),方法还能使用;
                        public void interrupt():中断线程,表示中断线程的一种状态,程序还能执行;
                wait()和sleep()的区别:
                        wait(): wait()调用的,立即释放锁(同步锁/Lock锁);

                        sleep()::线程睡眠,调用不会释放锁;

        public final void stop():强迫线程停止执行,不会执行了(过时了),方法能使用的;
        解释:在ThreadStop类中线程设点的是睡眠十秒,但是在主线程中,如果三秒醒不来,那么就中断线程,这时候ThreadStop类中的线程就会报异常,输出一句话;

        举例:

class ThreadStop extends Thread {
	
	@Override
	public void run() {
		System.out.println("程序开始了....");
		
		//睡秒10秒钟
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			//e.printStackTrace();
			System.out.println("程序出现异常了...");
		}
		
		System.out.println("程序结束了....");
	}
}

public class ThreadStopDemo {
	
	public static void main(String[] args) {
		
		//创建ThreadStop类对象
		ThreadStop st = new ThreadStop() ;
		
		st.start() ;
		
		//如果3秒不醒来,我就干掉你
		try {
			st.sleep(3000);
			//st.stop();
			st.interrupt();// 中断
		} catch (InterruptedException e) {
			//e.printStackTrace();
			System.out.println("程序出现了中断异常");
		}
		
	}
}
        2> 实现多线程程序的第二种方式:
                 1) 自定义一个类,实现Runnable接口;
2) 实现接口中的run方法,对耗时的代码进行操作;

3) 然后在主线程中创建该了对象,将该类对象做为一个资源类,创建Threadd类的对象,将刚才的资源类作为参数进行传递;

        举例:

//自定义类实现接口,实现run方法
class MyThread implements Runnable {

	@Override
	public void run() {
		
		for(int x= 0; x <100 ; x ++) {
			//System.out.println(getName()+":"+x);
			System.out.println(Thread.currentThread().getName()+":"+x);
		}
	}

}


public class ThreadDemo {
	
	public static void main(String[] args) {
		
		//创建当前类对象
		MyThread my =new MyThread() ;
		
		//实现多线程
		//public Thread(Runnable target,String name)
		Thread t1 = new Thread(my, "高圆圆") ;
		Thread t2 = new Thread(my, "赵又廷") ;
		
		//启动线程
		t1.start();
		t2.start();
	}
}

如何解决多线程的安全问题:

         校验一个多线程程序是否有安全问题的隐患的前提条件:
                1> 当前程序是否为多线程环境;
                2> 是否有共享数据;
                3> 是否有多条语句对共享数据进行操作;

        注意:一般我们只能从第三条解决程序的安全问题;

        为了模拟更真实的场景,给程序加入延迟操作(线程睡眠100毫秒):
        举例:

package org.westos_03;

class SellTicket implements Runnable {
	
	//定义100张票
	private int tickets = 100 ;
        /*@Override
	public void run() {
		
		while(true) {
			
			//t1先进来  t2
			if(tickets>0) {
				//为了模拟更真实的场景(网络售票有延迟的),稍作休息
				try {
					//t1睡 t2睡
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//睡醒之后不一定能抢到;
				System.out.println(Thread.currentThread().getName()
						+"正在出售第"+(tickets--)+"张票");
				//100张票
				//为什么会出现同一张票被卖多次?
				*//**
				 * 出现同票的原因:CPU的执行有一个特点(具有原子性操作:最简单最基本的操作)
				 * t1线程进来,睡完了,100张票
				 * 原子性操作:记录以前的值   100
				 * 接着tickets-- :票变成99张票
				 * 在马上输出99张票之前,t2/t3进来睡一会,直接输出记录的以前那个tickets的值,这个值是100
				 * 出现:
				 * 	窗口1正在出售第100张票
				 * 	窗口3正在出售第99张票
				 * 	窗口2正在出售第99张票
				 * 
				 * 原子性操作
				 * 
				 *//*
			}
		}
	}*/
	
	
	@Override
	public void run() {
		
		
		while(true) {
			try {
				//t1睡 t2睡
				Thread.sleep(100); //t2睡
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			if(tickets>0) {
				//t1,t2,t3 三个线程执行run里面代码
				//为了模拟更真实的场景(网络售票有延迟的),稍作休息
				
				System.out.println(Thread.currentThread().getName()
						+"正在出售第"+(tickets--)+"张票");//0
				/**
				 * 理想状态:
				 * 		t1正在出售第3张票
				 * 		t3正在出售第2张票
				 * 		t2正在出售第1张票
				 * ...
				 * 		负票(存在有的线程没有睡醒,醒了之后不经过if判断,直接执行输出语句,这时候票变为0,同样的道理变为-1)
				 * 		t1出售第0张票		(延迟操作+线程的执行随机性)
				 * 		t3正在出售-1张票
				 * 
				 */
			}
		}
	}

}

/**
 *     为了模拟更真实的场景,加入延迟操作(让我们线程睡100毫秒)
 * 
 */
public class SellTicketDemo {

	public static void main(String[] args) {

                //创建资源类对象(共享资源类/目标对象)
                SellTicket st = new SellTicket() ;

                //创建线程类对象
                Thread t1 = new Thread(st, "窗口1") ;
                Thread t2 = new Thread(st ,"窗口2") ;
                Thread t3 = new Thread(st, "窗口3") ;

                //启动线程
                t1.start();
                t2.start();
                t3.start();
        }
}
        上述代码存在安全问题:
                1> 同一张票被卖了多次;
                        CPU的执行有一个特点(具有 原子性操作:最简单最基本的操作);
                2> 出现了0或者负票;
                        ( 延迟操作+线程的执行随机性);

        解决方案1:同步代码块;
        格式:
        synchronized(锁对象){
针对多条语句对共享数据操作代码;
}
                解释:
                        锁对象:肯定一个对象,随便创建一个对象(匿名对象) ,它可以使任意的一个Java类(引用类型);
                                注意:每一个线程使用的锁对象,只能是同一把锁,(可以将锁对象看成是门的开和关);
        举例:

package org.westos_04;

class SellTicket implements Runnable {
	
	//定义100张票
	private int tickets = 100 ;
	
	private Object obj = new Object() ;

	@Override
	public void run() {
		while(true) {
			
			//new Object():锁对象 (门和关)
			//t1,t2,t3
			synchronized(obj) {//t1进来,门一关,t2,t3进不来了
				if(tickets>0) {
					try {
						//睡眠:延迟
						Thread.sleep(100); 
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()
							+"正在出售第"+(tickets--)+"张票");//0,-1
				}
			}
			
		}
	}

}

public class SellTicketDemo {

        public static void main(String[] args) {

                //创建资源类对象(共享资源类/目标对象)
                SellTicket st = new SellTicket() ;

                //创建线程类对象
                Thread t1 = new Thread(st, "窗口1") ;
                Thread t2 = new Thread(st ,"窗口2") ;
                Thread t3 = new Thread(st, "窗口3") ;

                //启动线程
                t1.start();
                t2.start();
                t3.start();
        }
}
        解决方案2:Lock锁(需要去释放锁);
                Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作;
        举例:
package org.westos_07;

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

class SellTicket implements Runnable {

	// 定义票
	private int tickets = 100;
	// Object obj = new Object();

	// Jdk5.0以后,java提供了一个具体的锁: 接口:Lock
	private Lock lock = new ReentrantLock(); // 显示获取锁的前提,一定要创建Lock接口对象

	@Override
	public void run() {
		while (true) {
			try { // try...finally
				lock.lock(); // 获取锁 syncrhonized(obj)
				if (tickets > 0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

					System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票");
				}

			} finally {// 释放锁
				if (lock != null) {
					lock.unlock();
				}
			}
		}
	}
}

public class SellTicketDemo {

        public static void main(String[] args) {

                SellTicket st = new SellTicket() ;

                Thread t1 = new Thread(st,"窗口1") ;
                Thread t2 = new Thread(st,"窗口2") ;
                Thread t3 = new Thread(st,"窗口3") ;

                //启动线程
                t1.start(); 
                t2.start(); 
                t3.start();
        }
}

        虽然解决了多线程的安全问题,但还是有些问题:
                1> 执行效率低;
                2> 会产生死锁;
                        死锁:两个或两个以上的线程,在执行的过程中出现互相等待的情况,就叫做死锁;
        举例:

package org.westos_08;

class DieLock extends Thread {
		
	//声明一个成语变量
	private boolean flag ;
	
	public DieLock(boolean flag) {
		this.flag = flag ;
	}
	
	//重写run方法
	@Override
	public void run() {
		if(flag) {
			synchronized (MyLock.objA) {
				System.out.println("if ObjA");
					synchronized (MyLock.objB) {
						System.out.println("if objB");
					}
			}
		}else {
			synchronized (MyLock.objB) {
				System.out.println("else objB");
					synchronized (MyLock.objA) {
						System.out.println("else objA");
					}
			}	
		}
	}
	
	//只有当一个锁执行完毕才能释放这个锁;
	//加入flag为true,那么闲执行锁对象MyLock.objA,接着继续执行MyLock.objB,但是这时候else进来了,执行MyLock.objB,执行完,
	//就要接着执行MyLock.objA,但是这时候下边的锁对象在等待上边的锁释放,而上边的锁对象也在等待下边的锁释放,
	//造成了互相等待的结果,这就是死锁;
	
	/**
	 * 第一种情况:
	 * 		if ObjA
				else objB
				
		第二种情况
			else objB
				if ObjA
				
		第三种情况:
			理想状态
				else objB
				else objA
				if ObjA
				if objB
				
				if ObjA
				if objB
				else objB
				else objA	
	 */
}

//测试类
public class DieLockDemo {

        public static void main(String[] args) {

                //创建线程了对象
                DieLock dl1 = new DieLock(true) ;
                DieLock dl2 = new DieLock(false) ;

                //启动线程
                dl1.start();
                dl2.start();
        }
}
        死锁的解决方案:
                使用两个线程,消费者线程以及生产者线程;
                举例分析:
                        Student类:资源类;
         SetThread:设置学生的数据(生产者线程);
         GetThread:获取(输出)学生数据(消费者线程);

         StudentDemo:测试类;

        完整的解决死锁问题:需要使用的是Java的等待唤醒机制;
                notify():唤醒在此对象监视器上等待的单个线程,如果所有线程都在此对象上等待,则会选择唤醒其中一个线程;
        举例:
                消费者线程:

package org.westos_11;

//消费者线程
public class GetThread implements  Runnable {
		private Student s ;
		
		public GetThread(Student s) {
			this.s = s ;
		}
	
	@Override
	public void run() {
		//输出该学生数据
		//Student s = new Student() ;
		while(true) {
			synchronized (s) {
				//如果在flag为false的情况下,本身消费者有数据,那么需要等待线程输出数据;
				if(!s.flag) {
					try {
						s.wait();//和网络编程中TCP编程里面的accept() 都属于阻塞式方法 
						//消费线程等待,等待该线程先输出这些数据(立即释放锁对象)
						
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				//线程当前没有数据,一等待,消费者线程将锁对象已经释放掉了,
				//释放了之后,我们这个数据需要输出数据,而我现在没有数据,改值,唤醒
				System.out.println(s.name +"----"+s.age);//高圆圆---27
				
				//如果没有数据类,
				s.flag = false ;
				//通知t1线程,赶紧产生数据
				s.notify(); //唤醒单个线程
			}
			//张杨---27
			
		}
		
	}
}
                生产者线程:
package org.westos_11;

//生产者线程
public class SetThread  implements Runnable {
	
	private Student s ;
	
	public SetThread(Student s) {
		this.s = s ;
	}
	
	//定义一个变量
	private int x = 0 ;
	
	@Override
	public void run() {
		//设置学生数据
		//Student s = new Student() ;
		while(true) {
			synchronized (s) {
				//判断有没有数据的情况
				//如果在flag为true的情况下,本身没有数据,那么等待产生数据;
				if(s.flag) {
					try {
						s.wait();  //如果本身没有数据线程等待,产生数据;
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				if(x%2 ==0) {
					s.name = "高圆圆" ;	//高圆圆---27
					s.age = 27 ;
				}else {
					s.name = "张杨";
					//张杨
					s.age = 28 ;
				}
				x++ ;
				
				//如果有数据了,更改flag值
				s.flag = true ;//有数据了
				//通知t2线程消费数据,唤醒
				s.notify();  //唤醒t2线程,唤醒之后t1,t2都互相抢占
				
			}
			
		}
		
	}
}
                资源类:
ackage org.westos_11;

public class Student {
	
	String name ;
	int age ;
	
	boolean flag; //默认没有数据,如果是true,说明有数据
}
                测试类:
public class StudentDemo {

        public static void main(String[] args) {

                //针对同一个对象进行操作
                Student s = new Student() ;

                //创建线程类对象
                SetThread st = new SetThread(s) ;
                GetThread gt = new GetThread(s) ;

                //创建线程了对象
                Thread t1 = new Thread(st) ; //生产者
                Thread t2 = new Thread(gt) ;//消费者

                //启动线程
                t1.start();
                t2.start();
        }
}
        面试题:
                wait(),notify(),notifyAll() 这些方法为什么会定义在Object类中呢?
                        wait():导致当前线程等待;
                                注意:特点 ==> 等待的过程中会立即释放所对象,这样才能在下面的代码上更改唤醒notify();
          notify():唤醒在此对象监视器上等待的单个线程,如果所有线程都在此对象上等待,则会选择唤醒其中一个线程;
                                选择是任意性的,并在对实现做出决定时发生;
          notifyAll():唤醒在此对象监视器上等待的所有线程;
                 定义在Object类中的原因:
                        这些方法好像是属于线程的方法,但是Thread类中并没有这些方法,因为多线程中同步锁对象是任意的Java类,而这些方法都和锁对象有关系,所以定义在Object类;

线程组:

        程组表示一个线程的集合。此外,线程组也可以包含其他线程组(用完就没了);

        举例:

package org.westos_12;

class MyThread implements Runnable {

	@Override
	public void run() {
		for(int x = 0 ; x <100 ; x ++) {
			System.out.println(Thread.currentThread().getName()+":"+x);
		}

	}

}

//测试类
public class ThreadGroupDemo {
        public static void main(String[] args) {

                //获取线程组的名称
                //method1();

                //如何给多个线程设置一个线程组名称呢?
                method2();
        }

        private static void method2() {

                //public ThreadGroup(String name)构造一个新线程组
                ThreadGroup tg = new ThreadGroup("main-新的线程组") ;

                //共享资源类
                MyThread my = new MyThread() ;

                //Thread(ThreadGroup group, Runnable target, String name) 
                Thread t1 = new Thread(tg, my, "线程1") ;
                Thread t2 = new Thread(tg, my, "线程2") ;

                //直接获取线程组名称
                System.out.println(t1.getThreadGroup().getName());
                System.out.println(t2.getThreadGroup().getName());
                System.out.println(t1.getName());
        }

        private static void method1() {

                MyThread my = new MyThread() ;

                //创建线程类对象
                Thread t1 = new Thread(my, "线程1") ;
                Thread t2 = new Thread(my, "线程2") ;

                //public final ThreadGroup getThreadGroup()返回该线程所属的线程组
                ThreadGroup tg1 = t1.getThreadGroup() ;
                ThreadGroup tg2 = t2.getThreadGroup() ;

                //public final String getName():返回线程组的名称
                System.out.println(tg1.getName()); //main
                System.out.println(tg2.getName());//main

                //所有的线程它默认的线程组名称:main(主线程)
                //currentThread:正在执行的线程;
                System.out.println(Thread.currentThread().getThreadGroup().getName());//main
        }
}

线程池:

        多个线程执行完毕,它会重新回到线程池中,等待被利用,不会变成垃圾;
        特点:

                1> 节约成本;

                2> 线程执行完毕之后不会变成垃圾,重新回到线程池中,等待被利用;

        举例:

ackage org.westos_13;

class MyRunnable implements Runnable {

	@Override
	public void run() {
		for(int x = 0 ; x < 100 ; x ++) {
			System.out.println(Thread.currentThread().getName()+":"+x);
		}
	}
}

//测试类
public class ExceutorsDemo {

        public static void main(String[] args) {

                //创建一个线程池:返回一个接口;
                ExecutorService pool = Executors.newFixedThreadPool(2) ;//创建一个线程池中包含了2条线程

                //提交和Runnable接口的方法或者Callable(提交任务)
                pool.submit( new MyRunnable()) ;
                pool.submit( new MyRunnable()) ;

                //1表示只有一个线程池,2表示线程池中的对象编号;
                //pool-1-thread-2 :线程池-池数-线程类对象的描述-编号(从1开始)

                //关闭线程池
                pool.shutdown();

        }
}
        3>自定义类实现Callable接口;
         举例:
                MyCallable类:
package org.westos_14;

import java.util.concurrent.Callable;

//Callable的泛型的类型它是call方法的返回值类型
public class MyCallable implements Callable {

	@Override
	public Object call() throws Exception {
		for(int x = 0 ; x < 100 ; x ++) {
			System.out.println(Thread.currentThread().getName()+":"+x);
		}
		
		return null;
	}
}
                测试类:
public class ExecutorsDemo {
	
	public static void main(String[] args) {
		
		//创建线程池对象
		ExecutorService pool = Executors.newFixedThreadPool(2) ;
		
		//提交任务
		pool.submit(new MyCallable()) ;
		pool.submit(new MyCallable()) ;
		
		//关闭线程池
		pool.shutdown();
	}
	
}
        综合练习:分别计算每个线程的求和;
package org.westos_15;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {
	
	//定义个变量
	private int number ;

	public MyCallable(int number) {
		this.number = number;
	}
	
	@Override
	public Integer call() throws Exception {
		//定义最终结果变量
		int sum = 0 ;
		for(int x =1 ; x <=number ; x ++) {
			sum +=x ;
		}
		return sum;
	}

}

//测试类
package org.westos_15;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
 *分别计算每个线程的求和! 
 *
 */
public class ExecutorsTest {

        public static void main(String[] args) throws InterruptedException,ExecutionException {

                //创建线程池对象
                ExecutorService pool = Executors.newFixedThreadPool(2) ;

                //提交任务
                Future<Integer> f1 = pool.submit(new MyCallable(100)) ;
                Future<Integer> f2 = pool.submit(new MyCallable(200)) ;

                //V get():获取结果(Future中的方法)
                Integer i1 = f1.get() ;
                Integer i2 = f2.get() ;

                System.out.println(i1);
                System.out.println(i2);

                //关闭线程池
                pool.shutdown();
        }
}




猜你喜欢

转载自blog.csdn.net/Future_LL/article/details/80396221