Java day 20-21
来源:互联网 发布:7级防空火箭升级数据 编辑:程序博客网 时间:2024/05/22 12:39
Day20
1.多线程:如果一个程序的执行路径有多条.
单线程:程序的执行路径只有一条
面试题:Jvm,java虚拟机是多线程程序吗?
答:是多线程程序,由于java虚拟机中自带一个垃圾回收器,来确保程序不会轻易的造成内存溢出。
至少开启两条子线程:
当前程序在执行代码的时候,会开启main:主线程
垃圾回收器会开启一个垃圾回收线程,来确保程序不会内存异常,将不用的变量或者没有更多引用的对象来回收掉
2. 如何实现多线程程序?
要实现多线程程序,必须创建一个进程,
创建进程需要调用系统资源进行创建,但是Java语言是不能直接调用系统资源
C/C++语言是可以创建系统资源,然后使用Java语言掉C/C++已经封装好的东西,
Java---->类:Thread类
并发和并行
并发:指的是同一个时间点
并行:指的的是一个时间段
多线程程序实现的第一种方式:
1)自定一个类:MyThread 继承自Thread类
2)在MyThread类中重写Thread类中的run() :为什么重写run()
3)在主线程中,创建该类的实例对象,启动线程
启动线程不是调用run()方法,
strat()是线程开始执行的方法
run()方法调用相当于调用了一个普通方法,并不会出现线程随机性;而start()方法调用,其实是通过Jvm调用线程中的run()来进行多个线程抢占CPU执行权
如何获取线程的名称?
public final String getName()返回该线程的名称。
设置线程名称
public final void setName(String name)改变线程名称,使之与参数name 相同。
例:
public class ThreadDemo {
publicstatic void main(String[] args) {
//创建该线程的实例对象
//MyThread my = new MyThread();
//启动线程
//启动线程不是调用run()方法,
//strat()是线程开始执行的方法
//run()方法调用相当于调用了一个普通方法,并不会出现线程随机性;而start()方法调用,
//其实是通过Jvm调用线程中的run()来进行多个线程抢占CPU执行权
//my.start() ;
//第二次启动线程,会出现:非法线程状态异常
//当前my线程已经启动了,不能重新启动
//my.start();
//my.run();
//my.run();
MyThreadmy1 = new MyThread();
MyThreadmy2 = new MyThread();
//分别启动线程
my1.start();
my2.start();
}
}
class MyThread extends Thread {
//重写Thread类中的run()方法
publicvoid run() {
//耗时的操作,线程睡眠,线程等待,循环语句
for(int x = 0; x < 100; x++) {
System.out.println(x);
}
}
}
多线程实现的第二种方式:(实际开发中第二种比第一种应用更广泛)
开发步骤:
1)自定义一个类MyRunnable,该类实现Runnable接口
2)实现该接口中的run()方法
3)在主线程中创建该类的实例对象,
4)创建Thread类对象,将3)创建的这个对象作为参数进行传递
5)分别启动线程
例:
public class ThreadDemo2 {
publicstatic void main(String[] args) {
//1)创建MyRunnable实例对象
MyRunnablemy = new MyRunnable();
//2)创建线程类对象
//publicThread(Runnable target,String name)
Threadt1 = new Thread(my, "线程1");
Threadt2 = new Thread(my, "线程2");
//启动线程
t1.start();
t2.start();
}
}
class MyRunnable implements Runnable {
publicvoid run() {
for(intx = 0 ; x < 100 ; x ++){
//在控制台,打印每一个子线程的线程名称
//getName()是Thread类中的方法
//间接的使用Thread类的静态功能得到线程名称
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
面试题:多线程的实现方式有几种,分别是什么?
答三个方式,分别阐述
第三种:和线程池有关系(并且和Callable接口有关系)
如果这个题口头问你,那么直说两种可以:继承Thread类,实现Runnable接口
多线程实现的第三种方式:(实际开发中很少用到)
public static ExecutorServicenewFixedThreadPool(int nThreads)
Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法:
ExecutorsService :接口中的方法<T>Future<T> submit(Callable<T> task)
该返回值表示:异步计算的结果。
例:
importjava.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CallableDemo {
publicstatic void main(String[] args) {
//创建线程池对象,利用工厂类
ExecutorServiceThreadpool = Executors.newFixedThreadPool(2);
//提交Callable任务(异步任务)
Threadpool.submit(newMyCallable());//相当于线程中的start()方法
Threadpool.submit(newMyCallable());
//结束线程池
Threadpool.shutdown();
}
}
import java.util.concurrent.Callable;
public class MyCallable implementsCallable<Object> {
//call()方法的返回值是和Callable中的泛型是一致的!
publicObject call() throws Exception {
for(intx = 0 ; x < 100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
returnnull;
}
}
综合例题:三个窗口同时卖出100张票。
方法1:
public class ThreadDemo3 {
publicstatic void main(String[] args) {
Sellticketsst1 = new Selltickets();
Sellticketsst2 = new Selltickets();
Sellticketsst3 = new Selltickets();
st1.setName("窗口1");
st2.setName("窗口2");
st3.setName("窗口3");
st1.start();
st2.start();
st3.start();
}
}
class Selltickets extends Thread {
privatestatic int tickets = 100;
privateObject o = new Object();
privateDemo d = new Demo();
publicvoid run() {
while(true) {
synchronized(d) {
if(tickets > 0) {
try{
Thread.sleep(100);
}catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(getName()+ "正在出售第" + tickets + "张票!");
tickets--;
}
}
}
}
}
class Demo {
}
方法2:
public class ThreadDemo {
publicstatic void main(String[] args) {
Sellticketsst1 = new Selltickets();
Sellticketsst2 = new Selltickets();
Sellticketsst3 = new Selltickets();
st1.setName("窗口1");
st2.setName("窗口2");
st3.setName("窗口3");
st1.start();
st2.start();
st3.start();
}
}
class Selltickets extends Thread {
privatestatic int tickets = 100;
privatestatic Object o = new Object();
privatestatic Demo d = new Demo();
publicvoid run() {
while(true) {
synchronized(d) {
if (tickets > 0){
try{
Thread.sleep(50);
}catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(getName()+ "正在出售第" + (tickets--)
+"张票!");
}
}
}
}
}
class Demo {
}
3. public final int getPriority()返回线程的优先级。
线程的优先级有哪些?
默认优先级:5
java.lang.Thread
public static final int MAX_PRIORITY 10:最大优先级
优先级大的抢占到CPU的执行权大,并不代表就一定能抢到,因为线程的执行具有随机性。
public static final int MIN_PRIORITY 1:最小优先级
public static final int NORM_PRIORITY 5:默认优先级
例:
public class ThreadProrityDemo {
publicstatic void main(String[] args) {
//创建该线程的对象
MyPrioritymp1 = new MyPriority();
MyPrioritymp2 = new MyPriority();
MyPrioritymp3 = new MyPriority();
//获取线程的优先级
System.out.println(mp1.getPriority());//5默认
System.out.println(mp2.getPriority());//5默认
System.out.println(mp3.getPriority());//5默认
mp1.setName("Tom");
mp2.setName("Ammy");
mp3.setName("Lucy");
//给线程设置优先级
mp1.setPriority(10);
mp2.setPriority(1);
//启动线程
mp1.start();
mp2.start();
mp3.start();
}
}
class MyPriority extends Thread {
publicvoid run() {
for(int x = 0; x < 100; x++) {
System.out.println(getName()+ ":" + x);
}
}
}
4. 线程中一些方法
public final void stop():强迫线程停止执行
public void interrupt()中断线程。 表示中断线程一种状态
join()
yield()
stop()
setDeamon(boolean on):(用的多)
sleep():线程睡眠 (用的多)
wait():线程等待
方法:
1) public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
暂停当前线程执行其他线程,并不保证另一个线程就一定能抢占到CPU的执行权。
例:
public class YieldThreadDemo {
public static voidmain(String[] args) {
//创建线程类对象
YieldThread yt1 =new YieldThread();
YieldThread yt2 =new YieldThread();
//设置线程名称
yt1.setName("Tom");
yt2.setName("Anny");
//启动线程
yt1.start();
yt2.start();
}
}
//自定义类
class YieldThread extendsThread {
public void run() {
//yt1,yt2
for(int x =0 ; x<100 ; x ++){
System.out.println(getName()+":"+x);
Thread.yield();
}
}
}
2) public final void join()
throwsInterruptedException等待该线程终止。
例:
public class JoinDemo {
public static voidmain(String[] args) {
JoinThread jt1 =new JoinThread();
JoinThread jt2 =new JoinThread();
JoinThread jt3 =new JoinThread();
//设置线程名称
jt1.setName("Tom");
jt2.setName("Anny");
jt3.setName("Lucy");
//启动线程
jt1.start();
//设置线程等待该线程终止该方法必须要启动线程
try {
jt1.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
jt2.start();
jt3.start();
}
}
class JoinThread extends Thread {
public void run() {
for(int x = 0 ; x<100 ; x ++){
System.out.println(getName()+":"+x);
}
}
}
3) 线程停止:
public final void stop():强迫线程停止执行
public void interrupt()中断线程。
表示中断线程一种状态
例:
public class ThreadStopDemo {
public static voidmain(String[] args) {
//创建线程类对象
ThreadStopts = new ThreadStop();
ts.start();
//如果3秒中不醒来,干掉它
try {
Thread.sleep(3000);
//强迫线程停止执行
ts.interrupt();//中断一种状态
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
import java.util.Date;
public class ThreadStop extends Thread {
public void run() {
System.out.println("开始执行了.."+newDate());
//睡眠10秒中
try {
Thread.sleep(10000);
} catch(InterruptedException e) {
System.out.println("线程终止了!");
}
System.out.println("结束执行"+newDate());
}
4) public final void setDaemon(boolean on) on指定true,就是设置守护线程...
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。
jvm自动退出,对于主线程的数据如果直接输出完毕,对于两个守护线程来说不会立即消失,Jvm等会就自动退出.
例:
public class ThreadDemaonDemo {
public static voidmain(String[] args) {
//创建线程类对象
ThreadDeamon td1= new ThreadDeamon();
ThreadDeamon td2= new ThreadDeamon();
//设置线程名称
td1.setName("Tom");
td2.setName("Jeny");
td1.setDaemon(true);
td2.setDaemon(true);
//启动线程
td1.start();
td2.start();
Thread.currentThread().setName("Lucy");
for(int x = 0 ; x<5 ; x++){
System.out.println(Thread.currentThread().getName()+":"+x);//设置主线程
}
}
}
class ThreadDeamon extends Thread {
public void run(){
for(intx = 0 ; x <100 ; x ++){
System.out.println(getName()+":"+x);
}
}
}
5) 线程睡眠:
public static void sleep(long millis)
throwsInterruptedException在指定的毫秒数内让当前正在执行的线程休眠暂停执行。
例:
public class ThreadSleepDemo {
public static voidmain(String[] args) {
//创建线程类对象
ThreadSellp ts1 =new ThreadSellp();
ThreadSellp ts2 =new ThreadSellp();
ThreadSellp ts3 =new ThreadSellp();
//设置线程名称
ts1.setName("线程1");
ts2.setName("线程2");
ts3.setName("线程3");
//启动线程
ts1.start();
ts2.start();
ts3.start();
}
}
import java.util.Date;
public class ThreadSellp extends Thread {
public void run() {
//ts1,ts2,ts3
for(int x = 0 ; x<100 ; x ++){
System.out.println(getName()+":"+x+",日期:"+newDate());
//睡眠1秒中:2000毫秒
try {
Thread.sleep(2000);//此方法本身就抛出一个异常
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
6. 线程安全的类有哪些?
Vector
StringBuffer
Hasttable
public class ThreadDemo {
public static voidmain(String[] args) {
//1)集合里面的Vector集合
Vector<String>v = new Vector<String>();
//2)字符串缓冲区
StringBuffer sb =new StringBuffer("Hello");
//3)Map集合中的子实现类:Hashtable
Hashtable<String,String> hm = new Hashtable<String,String>();
//从集合中来看,vector集合是一个安全的类,实际开发也不怎么用它
//Collections:针对集合操作的工具类
//public static<T> List<T> synchronizedList(List<T> list)返回指定列表支持的同步(线程安全的)列表
ArrayList list =new ArrayList();
List l =Collections.synchronizedList(list);
}
}
Day21
1. 使用同步机制的这种方式解决线程安全问题,但是不知道具体的锁对象在哪里添加,并且锁对象在哪里释放锁对象,对于这种情况Jdk5以后Java提供了一个更具体的锁对象:Lock。
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作
Lock是一个接口,所以它在使用的是 ReentrantLock子实现类
public void lock()获取锁。
public void unlock()试图释放此锁
没有抛出具体的异常,需要捕获异常
捕获异常标准格式:try...catch...finally
变形格式:try...finally...
例:
public class SellTicketsDemo {
public static voidmain(String[] args) {
//创建资源对象
SellTickets st =new SellTickets();
//创建线程对象
Thread t1 = newThread(st, "窗口1");
Thread t2 = newThread(st, "窗口2");
Thread t3 = newThread(st, "窗口3");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SellTickets implements Runnable {
private int tickets = 100;
// 定义一个具体锁对象
private Lock lock = newReentrantLock();
// 捕获异常标准格式:try...catch...finally
// 变形格式:try...finally...
public void run() {
// 假设电影院一直有票
while (true) {
try {
//获取锁
lock.lock();
if(tickets > 0) {
//加入延迟操作
try{
Thread.sleep(50);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票");
}
}finally {
//释放锁对象
lock.unlock();
}
}
}
}
2. 使用同步机制可以解决多线程的安全问题,但是自身也会有弊端:
1)同步---->执行效率低(每一个线程在抢占到CPU的执行权,会去将(门)关闭,别的线程进不来)
2)容易出现死锁现象
死锁线程:两个或者两个以上的线程出现了互相等待的情况,就会出现死锁。
例:
中国人和美国人吃饭
中国人:一双筷子
美国人:一把刀,一把叉
现在:
中国人:一根筷子和一把刀
美国人:一根筷子和一把叉
public class DeadLockDemo {
public static void main(String[] args) {
//创建线程类对象
DeadLock dl1 =new DeadLock(true);
DeadLock dl2 =new DeadLock(false);
//启动线程
dl1.start();
dl2.start();
}
// 运行时可能出现的情况:
// if objA else objB
// else objB if objA
// 理想状态:
// if objA
// if objB
// else objB
// else objA
}
public class DeadLock extends Thread {
// 定义一个成员变量
private boolean flag;
public DeadLock(booleanflag) {
this.flag = flag;
}
public void run() {
// dl1,dl2线程
if (flag) {
synchronized(MyLock.objA) {
System.out.println("ifobjA");
synchronized(MyLock.objB) {
System.out.println("ifobjB");
}
} // 代码执行完毕,objA锁相当于才能被释放掉
} else {
// dl2
synchronized(MyLock.objB) {
System.out.println("elseobjB");
synchronized(MyLock.objA) {
System.out.println("elseobjA");
}
}
}
}
}
class MyLock {
// 创建两把锁对象
public static final ObjectobjA = new Object();
public static final ObjectobjB = new Object();
}
3. 分析:
提供:资源对象:Student类:提供一些成员变量:姓名和年龄
生产者线程:SetThread类:生产一些学生数据(设置学生数据)
消费者线程:GetThread类:输出学生数据
测试类:StudentDemo类,实现多线程环境
操作:
使用刚才的这几个类:模拟生产消费者模式,生产者SetThread产生学生数据,而GetThread消费者线程输出学生数据,发现一个问题, 问题:输出学生数据的时候,是null 0。
对于每一个线程都在创建自己的学生对象,两个线程操作的两个对象而不是同一个对象,所以应该解决:将学生对象成员变量,然后通过构造方法进行传递,在测试类中,创建学生对象(同一个资源对象)让多个线程对这个学生对象进行操作。
public class StudentDemo1 {
public static voidmain(String[] args) {
// 创建一个学生对象
Student s = new Student();
// 创建自定义线程类对象
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s);
// 创建线程类对象
Thread t1 = newThread(st);
Thread t2 = newThread(gt);
// 启动线程
t1.start();
t2.start();
}
}
//学生类
class Student {
String name;
int age;
}
// 生产者线程
class SetThread implements Runnable {
private Student s;
public SetThread(Student s) {
this.s = s;
}
public void run() {
// 设置学生数据
s.name ="Tom";
s.age = 23;
}
}
// 消费者线程
class GetThread implements Runnable {
private Student s;
//构造方法
public GetThread(Students) {
this.s = s;
}
public void run() {
// 输出语句
System.out.println(s.name+ " " + s.age);
}
}
改进:为了数据多并且效果更明显,加入循环语句进行操作,给生产者线程和消费者线程分别加入循环语句(while循环)
public class StudentDemo2 {
public static voidmain(String[] args) {
// 创建一个学生对象
Student1 s = newStudent1();
// 创建自定义线程类对象
SetThread1 st =new SetThread1(s);
GetThread1 gt =new GetThread1(s);
// 创建线程类对象
Thread t1 = newThread(st);
Thread t2 = newThread(gt);
// 启动线程
t1.start();
t2.start();
}
}
//学生类
class Student1 {
String name;
int age;
}
// 生产者线程
class SetThread1 implements Runnable {
private Student1 s;
public SetThread1(Student1s) {
this.s = s;
}
private int x = 0;
public void run() {
while (true) {
// 同步机制进行操作
synchronized(s) {
if(x % 2 == 0) {
//x = 0
//设置学生数据
s.name= "Anny";
s.age= 33;
}else {
//设置学生数据
s.name= "Lucy";
s.age= 22;
}
x++;
}
}
}
}
// 消费者线程
class GetThread1 implements Runnable {
private Student1 s;
public GetThread1(Student1s) {
this.s = s;
}
public void run() {
while (true) {
synchronized(s) {
//输出语句
System.out.println(s.name+ " " + s.age);
}
}
}
}
改进之后出现两个问题:
1)同一个数据打印多次 //CPU一点点时间片足够执行很多次。
2)并且年龄和姓名不符合线程的随机性导致的。
优化改进之后,这些问题就说明当前多线程有安全问题: 多线程安全问题的标准: 1)是否是多线程环境
2)是否有共享数据
3)是否有多条语句对共享数据操作
当前是多线程环境,有共享数据,有多条语句对共享数据:s.name,s.age
使用同步机制来解决这个问题:将多条语句对共享数据进包装
使用同步机制去解决线程的安全问题,但是又有一个新的问题: 测试的时候,数据打印一打一大片,体验不好。
需求:让这个数据依次进行打印控制台,要使用这种方式去解决,利用Java等待唤醒机制。
public class StudentDemo3 {
public static voidmain(String[] args) {
// 创建学生对象
Student2 s = newStudent2();
SetThread2 st =new SetThread2(s);
GetThread2 gt =new GetThread2(s);
// 创建线程类对象
Thread t1 = newThread(st);
Thread t2 = newThread(gt);
// 启动线程
t1.start();
t2.start();
}
}
class Student2 {
String name;
int age;
// 声明一个变量
boolean flag; // 默认没有数据,如果true,则说明有数据
}
// 生产者线程
class SetThread2 implements Runnable {
private Student2 s;
public SetThread2(Student2s) {
this.s = s;
}
private int x = 0;
public void run() {
while (true) {
// 同步机制进行操作
synchronized(s) {
//判断有没有数据
if(s.flag) {
//处于等待状态
try{
s.wait();//阻塞式方法,立即释放锁
}catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x % 2 == 0) {
//x = 0
//设置学生数据
s.name= "Jeny";
s.age= 33;
}else {
//设置学生数据
s.name= "Lucy";
s.age= 27;
}
x++;
//修改标记
s.flag= true;// 有数据
//通知t2:消费者线程来消费数据
s.notify();//唤醒等待这种状态
}
}
}
}
// 消费者线程
class GetThread2 implements Runnable {
private Student2 s;
public GetThread2(Student2s) {
this.s = s;
}
public void run() {
while (true) {
synchronized(s) {
//判断有没有数据
if(!s.flag) {
try{
s.wait();//调用的时候,会立即释放锁
}catch (InterruptedException e) {
e.printStackTrace();
}
}
//输出语句
System.out.println(s.name+ " " + s.age);
//修改标记
s.flag= false;// 消费者线程
//通知对方(t1线程),消费者线程没有数据类,赶紧来消费
s.notify();// 唤醒t1线程
}
}
}
}
再次改进:(最终版代码)
现在将资源对象Student中的成员变量私有化
并且给当前类中提供两个方法,同步方法
在两个线程:生产者线程和消费者中线程,注意调用这两个方法就可以了
public class StudentDemo4 {
public static voidmain(String[] args) {
//创建一个资源对象
Student3 s = newStudent3();
//创建资源对象
SetThread3 st =new SetThread3(s);
GetThread3 gt =new GetThread3(s);
//创建线程类对象
Thread t1 = newThread(st);
Thread t2 = newThread(gt);
//分别启动线程
t1.start();
t2.start();
}
}
class Student3 {
private String name;
private int age;
//声明一个变量
private boolean flag; //默认没有数据,如果true,则说明有数据
public synchronized voidset(String name, int age) {
// 同步机制进行操作
// 判断有没有数据
if (this.flag) {
// 处于等待状态
try {
this.wait();//阻塞式方法,立即释放锁 notify notifyAll();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
//设置学生数据
this.name = name;
this.age = age;
//修改标记
this.flag = true;//有数据
//通知t2:消费者线程来消费数据
this.notify() ;//唤醒等待这种状态
}
public synchronized voidget(){
if(!this.flag){
try{
this.wait();//调用的时候,会立即释放锁
}catch (InterruptedException e) {
e.printStackTrace();
}
}
//输出语句
System.out.println(this.name+" "+this.age);
//修改标记
this.flag= false ;//消费者线程
//通知对方(t1线程),消费者线程没有数据类,赶紧来消费
this.notify();//唤醒t1线程
}
}
//生产者线程
class SetThread3 implements Runnable {
private Student3 s;
public SetThread3(Student3s){
this.s = s;
}
private int x = 0;
public void run() {
while(true){
if(x %2==0){
s.set("Anny",33);
}else{
s.set("Lucy",22);
}
x ++;
}
}
}
//消费者线程
class GetThread3 implements Runnable {
private Student3 s;
public GetThread3(Student3s){
this.s = s;
}
public void run() {
while (true) {
// 调用方法
s.get();
}
}
}
4. 线程组表示一个线程的集合:Java允许一个线程中有多个线程
public final ThreadGroup getThreadGroup()返回该线程所属的线程组
public class ThreadGroupDemo {
public static voidmain(String[] args) {
// method1();
method2();
}
//给每一个子线程可以设置线程名称
private static voidmethod2() {
//设置线程组名称
// public ThreadGroup(Stringname)构造一个新线程组
ThreadGroup tg =new ThreadGroup("新的线程组");
//创建资源对象
MyRunnable my =new MyRunnable();
//创建线程类对象,将线程组对象作为参数进行传递,使用Thread类的构造方法
//publicThread(ThreadGroup group,Runnable target ,String name){}
Thread t1 = newThread(tg, my, "线程1");//打印:新的线程组
Thread t2 = newThread(tg, my, "线程2");//打印:新的线程组
// public finalThreadGroup getThreadGroup()返回该线程所属的线程组
ThreadGroup tg1 =t1.getThreadGroup();
ThreadGroup tg2 =t2.getThreadGroup();
//获取打印子线程名
System.out.println(tg1.getName());
System.out.println(tg2.getName());
tg.setDaemon(true);//将线程组中的所有的线程都设置为守护线程(后台线程)
}
//获取子线程的默认线程组名
private static voidmethod1() {
//创建资源对象
MyRunnable my =new MyRunnable();
//创建两个线程类对象
Thread t1 = newThread(my);
Thread t2 = newThread(my);
//获取线程组对象
// public finalThreadGroup getThreadGroup()返回该线程所属的线程组
ThreadGroup tg1 =t1.getThreadGroup();
ThreadGroup tg2 =t2.getThreadGroup();
// public finalThreadGroup getName()获取t1,和t2线程所在的线程名称
String name1 = tg1.getName();
String name2 =tg2.getName();
//子线程默认的线程组名称:main线程
System.out.println(name1);//main
System.out.println(name2);//main
//所有的线程它的默认线程组名称就是main
System.out.println(Thread.currentThread().getThreadGroup().getName());//main
}
}
public class MyRunnable implements Runnable {
public void run() {
for(int x = 0 ; x<100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
5. JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法:
public static ExecutorService newFixedThreadPool(int nThreads)
Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程。
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法:
ExecutorsService :接口中的方法
Future<?> submit(Runnable task)<T> Future<T>submit(Callable<T> task)
线程池的好处:节约成本,很多子线程调用完毕不会立即被回收掉,而是会回到线程池中被多次利用。
例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorsDemo {
public static voidmain(String[] args) {
// 创建线程池对象,使用Executors工厂类
// public staticExecutorService newFixedThreadPool(int nThreads)
ExecutorServicepool = Executors.newFixedThreadPool(2);
// 使用ExecutorService(跟踪多个异步任务)一些方法
// 使用submit(Runnabletarget):提交多个任务
pool.submit(newMyRunnable());
pool.submit(newMyRunnable());
// 结束线程池
pool.shutdown();
}
}
public class MyRunnable implements Runnable {
@Override
public void run() {
//for循环
for(int x = 0 ; x< 100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
6. 线程求和
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableDemo {
public static voidmain(String[] args) throws InterruptedException, ExecutionException {
//创建线程池对象,利用工厂类:Executors
ExecutorServiceThreadPool = Executors.newFixedThreadPool(2) ;
//提交2异步任务,分别计算1-100,1-200之间的和
Future<Integer>f1 = ThreadPool.submit(new MyCallable(100)) ;
Future<Integer>f2 = ThreadPool.submit(new MyCallable(200)) ;
//分别调用Future接口中 get()方法,返回具体的结果
Integer v1 =f1.get() ;
Integer v2 =f2.get() ;
//输出结果
System.out.println("v1:"+v1);
System.out.println("v2:"+v2);
}
}
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
private int number ;
public MyCallable(intnumber){
this.number =number ;
}
public Integer call()throws Exception {
//定义最终结果变量
int sum = 0 ;
for(int x = 1 ; x<=number; x ++ ){
sum += x;
}
return sum;
}
}
7. JavaSe中的定时器:
Timer:
常用的几个方法:
public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
public void schedule(TimerTask task, long delay, long period)在多少毫秒后,执行任务,并且每个多少毫秒重复执行
public void cancel()终止此计时器,丢弃所有当前已安排的任务
例:
import java.util.Timer;
import java.util.TimerTask;
public class TimerDemo {
public static voidmain(String[] args) {
// public Timer()创建一个新计时器。
Timer t = newTimer();
// TimerTask:需要被执行的任务类是一个抽象类,所以不能直接实例化
t.schedule(newMyTask(t), 3000);
}
}
class MyTask extends TimerTask {
private Timer t;
public MyTask() {
}
public MyTask(Timer t) {
this.t = t;
}
public void run() {
System.out.println("你弱爆了!!!");
t.cancel();// 取消任务
}
}
8. 在指定的时间删除的指定目录
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class DeleteDemo {
public static voidmain(String[] args) throws ParseException {
//创建一个定时器对象
Timer t = new Timer() ;
//public voidschedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
//定义日期格式
String dateStr ="2017-12-5 21:21:00" ;
//解析成Date对象
//创建SimpleDateFormat对象
SimpleDateFormatsdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
//解析方法
Date date = sdf.parse(dateStr) ;
//调用定时器的这个在规定时间内执行某个任务的方法
t.schedule(newDeleteFolder(), date) ;
}
}
class DeleteFolder extends TimerTask{
public void run() {
//封装当前项目下的这个demo文件
File srcFolder =new File("Demo") ;
deleteFolder(srcFolder);
}
//递归删除
private voiddeleteFolder(File srcFolder) {
//获取当前srcFolder下面的所有的文件以及文件夹的File数组
File[] fileArray= srcFolder.listFiles();
//对该对象非空判断
if(fileArray!=null){
//增强for遍历
for(Filefile :fileArray){
//继续判断file对象是否是文件夹
if(file.isDirectory()){
//回到删除目录的方法
deleteFolder(file);
}else{
//不是目录,是文件,直接删除
System.out.println(file.getName()+"---"+file.delete());
}
}
System.out.println(srcFolder.getName()+"----"+srcFolder.delete());
}
}
}
9. 多线程中匿名内部类的方式
格式:
new 类名(具体类,抽象类),接口(){
重写/实现方法;
}
匿名内部类的本质:继承了该类或者是实现该接口的子类对象。
例:
public class ThreadDemo2 {
public static voidmain(String[] args) {
//继承自Thread类
new Thread(){
publicvoid run() {
//for循环
for(intx = 0 ; x <100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}.start() ;//启动线程
//Runnable接口的方式
new Thread(newRunnable() {
publicvoid run() {
//for循环
for(intx = 0 ; x < 100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}).start() ;
new Thread(newRunnable() {
publicvoid run() {
for(intx = 0 ; x <100 ; x ++){
System.out.println("hello"+x);
}
}
}){
publicvoid run() {
for(intx = 0 ; x <100 ; x ++){
System.out.println("world "+x);
}
}
}.start();
}
}
- Java day 20-21
- JAVA DAY DAY UP
- Java自学日记 day 20
- Java SE 20th day:NET Operation
- 21 day
- Effective Java读书笔记二一(Java Tips.Day.21)
- day day up--Java多线程理论知识碎片
- Effective Java读书笔记二十(Java Tips.Day.20)
- java tech day
- java高新技术day-1
- java高新技术day-2
- java高新技术day-3
- java 基础知识--one day!
- java新0day
- Java First Day 基础知识
- Java Second Day
- java新0day
- Java Day 3
- 安装ThinkPHP5.0.12遇到的小问题
- Android 使用代理加载插件
- linux 查看cpu
- java实现语法分析
- 171207之反编译插件jd-eclipse
- Java day 20-21
- [机器学习:李宏毅]24、SVM
- Virsh 虚拟机迁移
- 数据挖掘-处理缺失值
- MySql 外键约束 之CASCADE、SET NULL、RESTRICT、NO ACTION分析和作用
- MyEclipse和Eclipse中jsp、html格式化自动排版问题
- MaterialRefreshLayout 实现下拉刷新 和 上拉加载
- Java小对象的解决之道——对象池(Object Pool)的设计与应用
- java实现页式存储管理