day20
一、多线程实现的第一种方式:继承Thread类
1、多线程的实现方式一:继承Thread类
* 1)自定一个类:MyThread 继承自Thread类
* 2)在MyThread类中重写Thread类中的run()
* 3)在主线程中,创建该类的实例对象,启动线程
package org.westos_02_实现多线程第一种方式_继承Thread;
/**
* 多线程程序实现方式1:
* 1)自定一个类:MyThread 继承自Thread类
* 2)在MyThread类中重写Thread类中的run()
* 3)在主线程中,创建该类的实例对象,启动线程
* @author 小鑫
*/
public class ThreadDemo {
public static void main(String[] args) {
//创建该线程的实例对象
MyThread t1 = new MyThread();
//启动线程
//t.run();
//启动线程不是调用run()方法,run()方法只是一个普通的方法,并不会出现线程随机性
//启动线程用的是start()方法,通过JVM调用线程中的run()来进行多个线程抢占cpu执行权
t1.start();
//t.start();//java.lang.IllegalThreadStateException
//同一个对象线程只能启动一次,第二次报异常:非法线程状态异常
MyThread t2 = new MyThread();
t2.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println("hello" + x);
}
}
}
2、获取多线程名称
package org.westos_03_获取多线程名称;
/**
* public final String getName()返回该线程的名称。
* public final void setName(String name)改变线程名称,使之与参数 name 相同。
* public static Thread currentThread():表示正在运行的线程
* @author 小鑫
*
*/
public class ThreadDemo {
public static void main(String[] args) {
//无参构造形式
//wuCan();
//有参构造
youCan();
}
private static void youCan() {
//有参构造方式
//创建线程类实例
MyThread my1 = new MyThread("王五");
MyThread my2 = new MyThread("赵六");
//启动线程
my1.start();
my2.start();
}
private static void wuCan() {
//创建线程类的实例
//无参构造方式
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
//设置名称
//public final void setName(String name)
my1.setName("张三");
my1.setName("李四");
//public static Thread currentThread():表示正在运行的线程
//默认所有的子线程的都在主线程中
System.out.println(Thread.currentThread().getName());//main
//分别启动线程
my1.start();
my2.start();
}
}
class MyThread extends Thread{
//无参构造
public MyThread(){
}
//有参构造
public MyThread(String name){
super(name);
}
@Override
////my1和my2子线程都会执行这段代码,两个子线程在互相抢占CPU的执行权
public void run() {
for(int x=0;x<100;x++){
System.out.println("hello"+x);
}
}
}
3、线程终止
public final void join() throws InterruptedException等待该线程终止。
package org.westos_04_线程终止_线程暂停_线程优先级;
/**
* public final void join()
throws InterruptedException等待该线程终止。
* 其他线程要等待该线程终止后才能开始运行
* @author 小鑫
*/
public class JoinDemo {
public static void main(String[] args) {
//无参构造
//创建线程实例对象
MyJoin mj1 = new MyJoin();
MyJoin mj2 = new MyJoin();
MyJoin mj3 = new MyJoin();
//设置名称
mj1.setName("张三");
mj2.setName("李四");
mj3.setName("王五");
//启动线程
mj1.start();
try {
mj1.join();
} catch (InterruptedException e) {
// 中断异常
e.printStackTrace();
}
mj2.start();
mj3.start();
}
}
class MyJoin extends Thread{
@Override
public void run() {
for(int x=0;x<100;x++){
System.out.println(getName()+":"+x);
}
}
}
4、线程的暂停
public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
package org.westos_04_线程终止_线程暂停_线程优先级;
/**
* public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
* 暂停当前线程执行其他线程,并不保证另一个线程就一定能抢占到CPU的执行权
* 暂停之后,二者重新抢夺CPU执行权
* @author 小鑫
*
*/
public class YieldThreadDemo {
public static void main(String[] args) {
//创建线程实例对象
//无参构造
MyYieldThread my1 = new MyYieldThread();
MyYieldThread my2 = new MyYieldThread();
//设置名称
my1.setName("张三");
my2.setName("李四");
//启动线程
my1.start();
my2.start();
}
}
class MyYieldThread extends Thread{
@Override
public void run() {
for(int x=0;x<100;x++){
System.out.println(getName()+":"+x);
//public static void yield():暂停当前线程
Thread.yield();
}
}
}
5、线程的优先级
public final int getPriority()返回线程的优先级。
package org.westos_04_线程终止_线程暂停_线程优先级;
/**
* 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 :默认优先级
* @author 小鑫
*
*/
public class PriorityDemo {
public static void main(String[] args) {
//有参构造
//创建线程实例对象
MyPaiority mp1 = new MyPaiority("刘备");
MyPaiority mp2 = new MyPaiority("关羽");
MyPaiority mp3 = new MyPaiority("张飞");
//获取优先级
//System.out.println(mp1.getPriority());//5
//System.out.println(mp2.getPriority());//5
//System.out.println(mp3.getPriority());//5
//设置优先级
mp1.setPriority(10);
mp3.setPriority(1);
//启动线程
mp1.start();
mp2.start();
mp3.start();
}
}
class MyPaiority extends Thread{
public MyPaiority() {
super();
}
public MyPaiority(String name) {
super(name);
}
@Override
public void run() {
for(int x=0;x<100;x++){
System.out.println(getName()+":"+x);
}
}
}
6、线程睡眠
package org.westos_05_线程睡眠_线程停止_守护线程;
import java.util.Date;
public class SleepDemo {
public static void main(String[] args) {
//创建线程实例对象
ThreadSleep ts1 = new ThreadSleep();
ThreadSleep ts2 = new ThreadSleep();
ThreadSleep ts3 = new ThreadSleep();
//设置名称
ts1.setName("线程1");
ts2.setName("线程2");
ts3.setName("线程3");
//启动线程
ts1.start();
ts2.start();
ts3.start();
}
}
class ThreadSleep extends Thread{
@Override
public void run() {
for(int x=1;x<=30;x++){
System.out.println(getName()+":"+x+",日期:"+new Date());
//睡眠1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
7、停止线程和中断线程
public final void stop():强迫线程停止执行
public void interrupt()中断线程。 表示中断线程一种状态
package org.westos_05_线程睡眠_线程停止_守护线程;
import java.util.Date;
/**
* public final void stop():强迫线程停止执行
* public void interrupt()中断线程。 表示中断线程一种状态
* @author 小鑫
*
*/
public class StopDemo {
public static void main(String[] args) {
//创建线程实例对象
StopThread st = new StopThread();
//启动线程
st.start();
//开始执行Tue Dec 05 20:12:10 CST 2017
//结束执行Tue Dec 05 20:12:15 CST 2017
//三秒睡不醒,停止它
try {
Thread.sleep(3000);
//st.stop();//中间那条线表示过时了
//开始执行Tue Dec 05 20:11:40 CST 2017
st.interrupt();
//开始执行Tue Dec 05 20:12:55 CST 2017
//线程睡着了
//结束执行Tue Dec 05 20:12:58 CST 2017
//能打印线程睡着了,说明走catch语句,即中断try语句
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class StopThread extends Thread{
@Override
public void run() {
System.out.println("开始执行"+new Date());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("线程睡着了");
}
System.out.println("结束执行"+new Date());
}
}
8、守护线程
public final void setDaemon(boolean on) on指定true,就是设置守护线程…
将该线程标记为守护线程或用户线程。
package org.westos_05_线程睡眠_线程停止_守护线程;
/**
* public final void setDaemon(boolean on) on指定true,就是设置守护线程...
* 将该线程标记为守护线程或用户线程。
* 当正在运行的线程都是守护线程时,Java 虚拟机退出。
* 该方法必须在启动线程前调用。
* jvm自动退出,对于主线程的数据如果直接输出完毕,对于两个守护线程来说不会立即消失,Jvm等会就自动退出.
* @author 小鑫
*
*/
public class DemaonDemo {
public static void main(String[] args) {
//创建线程实例对象
MyDemaonThread mt1 = new MyDemaonThread();
MyDemaonThread mt2 = new MyDemaonThread();
//设置名称
mt1.setName("守护1");
mt2.setName("守护2");
//设置守护线程
mt1.setDaemon(true);
mt2.setDaemon(true);
//启动线程
mt1.start();
mt2.start();
//设置被守护线程
Thread.currentThread().setName("被守护线程");
for(int x=0;x<5;x++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
class MyDemaonThread extends Thread{
@Override
public void run() {
for(int x=0;x<100;x++){
System.out.println(getName()+":"+x);
}
}
}
二、多线程实现的第二种方式:Runnable接口
1、多线程实现的第二种方式:Runnable接口
* 1)自定义一个类MyRunnable,该类实现Runnable接口
* 2)实现该接口中的run()方法
* 3)在主线程中创建该类的实例对象,
* 4)创建Thread类对象,将3)创建的这个对象作为参数进行传递
* 5)分别启动线程
package org.westos_06_实现多线程第二种方式_Runnable接口;
/**
* 多线程实现的第二种方式:(实际开发中第二种比第一种应用更广泛)
* 开发步骤:
* 1)自定义一个类MyRunnable,该类实现Runnable接口
* 2)实现该接口中的run()方法
* 3)在主线程中创建该类的实例对象,
* 4)创建Thread类对象,将3)创建的这个对象作为参数进行传递
* 5)分别启动线程
* @author 小鑫
*
*/
public class ThreadDemo {
public static void main(String[] args) {
//创建MyRunnable实例对象
MyRunnable my= new MyRunnable();
//创建线程对象
//public Thread(Runnable target)
//Thread t1 = new Thread(my);
//Thread t2 = new Thread(my);
//public Thread(Runnable target,String name)
Thread t1 = new Thread(my, "线程1");
Thread t2 = new Thread(my, "线程2");
t1.start();
t2.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for(int x=0;x<100;x++){
//getName()是Thread类中的方法,间接使用Thread类的静态功能获得线程名称
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
2、检验多线程安全问题的标准(以后在判断一个多线程序是否有安全问题的标准)
* 1)当前是否是一个多线程环境
* 2)多线程环境中是否有共享数据
* 3)是否有多条语句对共享数据进行操作
package org.westos_07_模拟多线程_电影院卖票案例;
/**
* 为了模拟电影院卖票更真实的场景,每一个窗口卖票应该延迟操作
* 在接口自实现类中,在run()方法中让每一个线程执行睡眠0.1秒
*
*加入延迟操作:
* 1)一张票可能被卖多次
* 100张票会出现多次
* CPU的执行具有原子性操作
* 2)可能出现负票
* 1,0,-1
* 延迟操作和线程随机性导致
*
*
*这两种情况都属于线程安全问题,现在写的这个代码是一种有问题的代码?
* 如何解决多线程的安全问题呢?
* 检验多线程安全问题的标准(以后在判断一个多线程序是否有安全问题的标准)
* 1)当前是否是一个多线程环境
* 2)多线程环境中是否有共享数据
* 3)是否有多条语句对共享数据进行操作
*
*就目前这个电影院卖票这个案例,
* 1)是多线程环境,因为要实现3个窗口同时卖票
* 2)有共享数据,比如:tickets
* 3)有多条语句对当前这个共享数据进行操作
*
*优化改进:
* 1)多线程环境和共享数据改变不了,突破口就是3)条件:将多条语句对共享数据的操作进行更改
*
* 将多条语句对共享数据进行操作的代码用代码块包起来
* 使用同步代码块:synchronized(同步锁对象){
* 多条语句对共享数据的操作;
* }
* @author 小鑫
*/
public class SellTicketDemo {
public static void main(String[] args) {
//创建线程实例对象
TicketThread tt1 = new TicketThread();
TicketThread tt2 = new TicketThread();
TicketThread tt3 = new TicketThread();
//设置名称
tt1.setName("窗口1");
tt2.setName("窗口2");
tt3.setName("窗口3");
//启动线程
tt1.start();
tt2.start();
tt3.start();
}
}
class TicketThread extends Thread{
//private int tickets=100;
//定义100张票,票被三个线程公用,用static修饰
private static int tickets=100;
@Override
public void run() {
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(tickets>0){
System.out.println(getName()+"正在出售第"+(tickets--)+"张票");
}
}
}
}
3、多线程同步机制
package org.westos_08_线程同步机制_电影院卖票案例;
/**
* 就目前这个电影院卖票这个案例, 1)是多线程环境,因为要实现3个窗口同时卖票 2)有共享数据,比如:tickets
* 3)有多条语句对当前这个共享数据进行操作
*
* 优化改进: 1)多线程环境和共享数据改变不了,突破口就是3)条件:将多条语句对共享数据的操作进行更改
*
* 将多条语句对共享数据进行操作的代码用代码块包起来 Java的同步机制: 使用同步代码块:synchronized(同步锁对象){
* 多条语句对共享数据的操作; }
*
* 同步锁对象:应该每一个线程都要使用这个锁对象(同步锁):理解为门的开和关 使用同步代码块可以解决线程安全问题
*
* @author 小鑫
*
*/
public class SellTicketDemo {
public static void main(String[] args) {
// 创建TicketThread对象
TicketThread tt = new TicketThread();
// 创建线程对象
Thread t1 = new Thread(tt, "窗口1");
Thread t2 = new Thread(tt, "窗口2");
Thread t3 = new Thread(tt, "窗口3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
}
class TicketThread implements Runnable {
// 定义100张票
private static int tickets = 100;
// 设置锁对象,三个线程必须使用同一个锁对象
// 可以是Object类型,任意的Java类
private Object obj = new Object();
@Override
public void run() {
// 一直邮有票
while (true) {
// 睡眠0.1秒
synchronized (obj) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票");
}
}
}
}
}
4、同步方法
package org.westos_09_线程同步机制_同步方法_电影院卖票案例;
/**
* 同步方法
* @author 小鑫
*/
public class SellTeckesDemo {
public static void main(String[] args) {
// 创建TecketThread对象
TecketThread tt = new TecketThread();
// 创建线程实例对象
Thread t1 = new Thread(tt, "窗口1");
Thread t2 = new Thread(tt, "窗口2");
Thread t3 = new Thread(tt, "窗口3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
}
class TecketThread implements Runnable {
// 定义100张被共用的票,不能修改
private static int tickets = 100;
// 创建锁对象
private Object obj = new Object();
private int x;
@Override
public void run() {
while (true) {
if (x % 2 == 0) {
//静态时的同步锁对象--->类名.class
//静态同步方法:要通过反射获取Class类对象(当前类的字节码文件对象)
synchronized (TecketThread.class) {
if (tickets > 0) {
try {
//睡眠0.1秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票");
}
}
} else {
//sellTicket();
}
}
}
// 非静态同步方法,锁对象是this
/*private synchronized void sellTicket() {
if (tickets > 0) {
// 设置线程睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第"
+ (tickets--) + "张票");
}
}*/
//静态同步方法,锁对象是(类名.class)
private static synchronized void sellTicket() {
if (tickets > 0) {
// 设置线程睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第"
+ (tickets--) + "张票");
}
}
}
day21
一、同步锁
1、Lock锁
* Jdk5以后Java提供了一个更具体的锁对象:Lock Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作
* Lock是一个接口,所以它在使用的是 ReentrantLock子实现类
* public void lock()获取锁。
package org.westos_01_Lock锁;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* public void lock()获取锁。
* public void unlock()试图释放此锁
*
* @author 小鑫
*/
public class SellTicketDemo {
public static void main(String[] args) {
// 创建TicketThread对象
TicketThread tt = new TicketThread();
// 创建线程实例对象
Thread t1 = new Thread(tt, "窗口1");
Thread t2 = new Thread(tt, "窗口2");
Thread t3 = new Thread(tt, "窗口3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
}
class TicketThread implements Runnable {
// 定义100张票
private static int tickets = 100;
// 锁对象
private Object obj = new Object();
// 定义一个具体锁对象
private Lock l = new ReentrantLock();
@Override
public void run() {
// oldMethod();
// 一直有票
while (true) {
// 获取锁
try {
l.lock();
if (tickets > 0) {
// 睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第"
+ (tickets--) + "张票");
}
} finally{
//释放锁对象
l.unlock();
}
}
}
private void oldMethod() {
// 一直有票
while (true) {
synchronized (obj) {
if (tickets > 0) {
// 睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票");
}
}
}
}
}
2、死锁现象
* 死锁线程:两个或者两个以上的线程出现了互相等待的情况,就会出现死锁!
package org.westos_02_死锁;
/**
* 使用同步机制可以解决多线程的安全问题,但是自身也会有弊端:
* 1)同步---->执行效率低(每一个线程在抢占到CPU的执行权,会去将(门)关闭,别的线程进不来)
* 2)容易出现死锁现象
* @author 小鑫
*/
public class DieLockDemo {
public static void main(String[] args) {
//创建线程对象
DieLock dl1 = new DieLock(true);
DieLock dl2 = new DieLock(false);
//启动线程
dl1.start();
dl2.start();
}
}
class MyLock{
//创建两把锁对象
public static final Object objA = new Object();
public static final Object objB = new Object();
}
class DieLock extends Thread{
//定义一个成员变量
private boolean flag;
public DieLock(boolean flag){
this.flag=flag;
}
@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");
}
}
}
}
}
3、生产者消费者模式
package org.westos_03_生产者消费者模式;
/**
*
* @author 小鑫
*/
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();
}
}
//资源对象类
class Student{
String name;
int age;
}
//生产者类
class SetThread implements Runnable{
private Student s;
public SetThread(Student s){
this.s=s;
}
@Override
public void run() {
//设置资源数据
s.name="张三";
s.age=30;
}
}
//消费者类
class GetThread implements Runnable{
private Student s;
public GetThread(Student s){
this.s=s;
}
@Override
public void run() {
System.out.println(s.name+"---"+s.age);
}
}
4、同步机制生产者消费者模式
package org.westos_04_同步生产者消费者模式;
/**
*
* @author 小鑫
*/
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();
}
}
// 学生资源对象类
class Student {
String name;
int age;
}
// 生产者线程
class SetThread implements Runnable {
private Student s;
public SetThread(Student s) {
this.s = s;
}
private int x;
@Override
public void run() {
// 同步机制
while (true) {
synchronized (s) {
if (x % 2 == 0) {
s.name = "张三";
s.age = 30;
} else {
s.name = "李四";
s.age = 40;
}
x++;
}
}
}
}
//消费者线程
class GetThread implements Runnable{
private Student s;
public GetThread(Student s){
this.s=s;
}
@Override
public void run() {
while(true){
synchronized (s) {
System.out.println(s.name + "---" + s.age);
}
}
}
}
5、同步机制等待唤醒机制生产者消费者模式
package org.westos_05_同步机制_等待唤醒机制_生产者消费者模式;
/**
*
* @author 小鑫
*/
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();
}
}
//资源对象学生类
class Student{
String name;
int age;
//声明标记
boolean flag;//默认没有数据,如果true,则说明有数据
}
//生产者线程
class SetThread implements Runnable{
private Student s;
public SetThread(Student s){
this.s=s;
}
private int x;
@Override
public void run() {
while(true){
//同步机制
synchronized(s){
//判断是否有数据
/**
* 如果生产者先抢到CPU执行权,判断是否有数据
* 如果没有数据,则释放锁对象,生产数据;
* 如果有数据了,修改标记,通知消费者消费数据,唤醒等待状态
*/
if(s.flag){
//等待
try {
s.wait();//阻塞式方法,立即释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x%2==0){
s.name="张三";
s.age=30;
}else{
s.name="李四";
s.age=40;
}
x++;
//修改标记
s.flag=true;
//有数据了,通知t2消费者线程来消费数据
//唤醒等待这种状态
s.notify();
}
}
}
}
//消费者线程
class GetThread implements Runnable{
private Student s;
public GetThread(Student s){
this.s=s;
}
@Override
public void run() {
while(true){
synchronized(s){
//判断是否有数据
/**
* 消费者先抢到CPU执行权,判断是否有数据,如果有数据则输出;
* 如果没有数据,立即释放锁对象,并修改标记,通知生产者生产数据,唤醒等待状态
*/
if(!s.flag){
try {
s.wait();//调用时立即释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.name+"---"+s.age);
//修改标记
s.flag=false;
//通知t1生产者线程,没有数据了,该生产数据了
//唤醒t1线程
s.notify();
}
}
}
}
6、最终版生产者消费者模式
package org.westos_06_最终版_生产者消费者模式;
/**
* 最终版代码:
* 现在将资源对象Student中的成员变量私有化
* 并且给当前类中提供两个方法,同步方法
* 在两个线程:生产者线程和消费者中线程,注意调用这两个方法就可以了!
* @author 小鑫
*
*/
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();
}
}
class Student{
private String name;
private int age;
//声明一个变量
private boolean flag;
//默认没有数据
//set(String name,int age)方法,产生数据数据
public synchronized void set(String name, int age){
//判断是否有数据
if(this.flag){
//没有数据,等待状态
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//产生数据
this.name=name;
this.age=age;
//修改标记
this.flag=true;
//有数据了,通知消费者线程
this.notify();//唤醒等待这种状态
}
public synchronized void get(){
if(!this.flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.name+"---"+this.age);
//修改标记
this.flag=false;
//通知生产者线程,没有数据,该生产数据
this.notify();//唤醒生产者线程
}
}
//生产者线程
class SetThread implements Runnable{
private Student s;
public SetThread(Student s){
this.s=s;
}
private int x;
@Override
public void run() {
while(true){
if(x%2==0){
s.set("张三", 30);
}else{
s.set("李四", 40);
}
x++;
}
}
}
//消费者线程
class GetThread implements Runnable{
private Student s;
public GetThread(Student s){
this.s=s;
}
@Override
public void run() {
while(true){
s.get();
}
}
}
二、线程组
- 线程组表示一个线程的集合:Java允许一个线程中有多个线程
package org.westos_07_线程组;
/**
* 线程组表示一个线程的集合:Java允许一个线程中有多个线程
* @author 小鑫
*/
public class ThreadGroupDemo {
public static void main(String[] args) {
//获取线程组名称
//method1();
//设置线程组名称
method2();
}
//设置线程组名称
private static void method2() {
//public ThreadGroup(String name)构造一个新线程组
ThreadGroup tg = new ThreadGroup("新线程");
//创建资源对象
MyRunnable my = new MyRunnable();
//public Thread(ThreadGroup group,Runnable target ,String name){}
//创建线程类对象,并且将线程组对象作为参数进行传递
Thread t1 = new Thread(tg, my, "线程1");
Thread t2 = new Thread(tg, my, "线程2");
ThreadGroup tg1 = t1.getThreadGroup();
ThreadGroup tg2 = t2.getThreadGroup();
System.out.println(tg1.getName());
System.out.println(tg2.getName());
}
//获取线程组名称
private static void method1() {
//创建资源对象
MyRunnable my = new MyRunnable();
//创建线程对象
Thread t1 = new Thread(my);
Thread t2 = new Thread(my);
//启动线程
//t1.start();
//t2.start();
//获取线程组对象
//public final ThreadGroup getThreadGroup()返回该线程所属的线程组
ThreadGroup tg1 = t1.getThreadGroup();
ThreadGroup tg2 = t2.getThreadGroup();
//获取线程组名称
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());
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
三、多线程实现的第三种方式
1、Executors工厂类产生线程池
package org.westos_08_线程池;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 多线程程序的实现方式3:
* Executors工厂类来产生线程池 public static ExecutorService
newFixedThreadPool(int nThreads) Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
* 方法的返回值是ExecutorService对象,该对象表示一个线程池 ExecutorsService :
* 接口中的方法 Future<?>submit(Runnable task) <T> Future<T> submit(Callable<T> task)
* @author 小鑫
*/
public class ExecutorsDemo {
public static void main(String[] args) {
//创建线程对象,使用Executors工厂类
//public static ExecutorService newFixedThreadPool(int nThreads)
ExecutorService pool = Executors.newFixedThreadPool(2);
//使用ExecutorsService(跟着多个异步任务)方法
//submit(Runnable task)
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();
//pool-1-thread-1:x
//pool-1-thread-2:x
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
2、Callable接口
package org.westos_08_线程池;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* ExecutorsService :接口中的方法
* <T> Future<T> submit(Callable<T> task)
* 该返回值表示:异步计算的结果!
* @author 小鑫
*/
public class CallableDemo {
public static void main(String[] args) {
//创建线程对象,工厂类
ExecutorService Threadpool = Executors.newFixedThreadPool(2);
//提交Callable任务(异步任务)
Threadpool.submit(new MyCallable());
Threadpool.submit(new MyCallable());
//结束线程
Threadpool.shutdown();
//pool-1-thread-1:x
//pool-1-thread-2:x
}
}
class MyCallable implements Callable<Object>{
@Override
public Object call() throws Exception {
for(int x=0;x<100;x++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
return null;
}
}
3、Callable接口求和
package org.westos_09_线程池Callable求和;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableDemo2 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//创建线程对象,工厂类
ExecutorService Threadpool = Executors.newFixedThreadPool(2);
//提交两个异步任务,计算1-100,1-200的和
Future<Integer> f1 = Threadpool.submit(new MyCallable(100));
Future<Integer> f2 = Threadpool.submit(new MyCallable(200));
//分别调用Future接口中 get()方法,返回具体的结果
Integer i1 = f1.get();
Integer i2 = f2.get();
System.out.println("1-100的和是:"+i1);
System.out.println("1-200的和是:"+i2);
//1-100的和是:5050
//1-200的和是:20100
}
}
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;
}
}
4、多线程匿名内部类
多线程中匿名内部类的方式
* new 类名(具体类,抽象类),接口{
* 重写/实现方法;
* }
匿名内部类本质:
* 继承该类或者实现该接口的子类对象
package org.westos_09_线程池Callable求和;
/**
* 多线程中匿名内部类的方式
* new 类名(具体类,抽象类),接口{
* 重写/实现方法;
* }
* 匿名内部类本质:
* 继承该类或者实现该接口的子类对象
* @author 小鑫
*/
public class ThreadDemo {
public static void main(String[] args) {
//继承Thread类
new Thread(){
@Override
public void run(){
for(int x=0;x<100;x++){
System.out.println(getName()+":"+x);
}
}
}.start();
//Runnable接口
new Thread(new Runnable(){
@Override
public void run(){
for(int x = 0 ; x < 100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
for(int x = 0 ; x <100 ; x ++){
System.out.println("hello"+x);
}
}
}){
@Override
public void run() {
for(int x = 0 ; x <100 ; x ++){
System.out.println("world"+x);
}
}
}.start();
}
}
四、定时器Timer
定时器: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()终止此计时器,丢弃所有当前已安排的任务
1、 public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
package org.westos_10_定时器Timer;
import java.util.Timer;
import java.util.TimerTask;
/**
* 需求:3秒后执行爆炸任务
* @author 小鑫
*/
public class TimerDemo {
public static void main(String[] args) {
//创建计时器
Timer t = new Timer();
//public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
t.schedule(new MyTask(t), 3000);
}
}
class MyTask extends TimerTask{
private Timer t;
public MyTask(){
}
public MyTask(Timer t){
this.t=t;
}
@Override
public void run() {
System.out.println("boom...");
t.cancel();//取消任务
}
}
2、安排在指定的时间执行指定的任务
package org.westos_10_定时器Timer;
import java.util.Timer;
import java.util.TimerTask;
/**
* public void schedule(TimerTask task, long delay, long period)
* 在多少毫秒后,执行任务,并且每个多少毫秒重复执行
*
* 需求:3秒后执行爆炸任务,每隔2秒重复爆炸
* @author 小鑫
*/
public class TimerDemo2 {
public static void main(String[] args) {
//创建计时器
Timer t = new Timer();
t.schedule(new MyTask2(), 3000, 2000);
}
}
class MyTask2 extends TimerTask{
@Override
public void run() {
System.out.println("boom...");
}
}
3、在指定的时间删除我们的指定目录
package org.westos_10_定时器Timer;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
* 需求:在指定的时间删除我们的指定目录
* @author 小鑫
*/
public class TimerTest {
public static void main(String[] args) throws ParseException {
//创建定时器
Timer t = new Timer();
//指定删除日期
String s="2017-12-8 10:40:00";
//创建SimpleDateFormat对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(s);
//public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
t.schedule(new DeleteFolder(), date);
}
}
class DeleteFolder extends TimerTask{
@Override
public void run() {
File srcFolder = new File("demo");
deleteFolder(srcFolder);
}
private void deleteFolder(File srcFolder) {
//获取srcFolder文件及文件夹数组
File[] fileArray = srcFolder.listFiles();
//非空判断
if(fileArray!=null){
for(File file:fileArray){
//判断是否是文件夹
if(file.isDirectory()){
//递归删除,回到该方法
deleteFolder(file);
}else{
//不是文件夹,直接删除
System.out.println(file.getName()+"---"+file.delete());
}
}
System.out.println(srcFolder.getName()+"---"+srcFolder.delete());
}
}
}
五、IO流存入文件注册登录案例
用户实体类
package org.westos_11_User;
/**
* 用户实体
* @author 小鑫
*
*/
public class User {
private String username;
private String password;
public User(){
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
注册登录接口
package org.westos_11_User;
public interface UserDao {
/**
* 用户登录功能
*
* @param username
* 登录输入的用户名
* @param password
* 登录输入的密码
* @return
* 返回是否登录成功
*/
public abstract boolean isLogin(String username, String password);
/**
* 用户注册功能
* @param user
*/
public abstract void regist(User user);
}
用户操作接口实现类
package org.westos_11_User;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* 用户操作接口实现类
* @author 小鑫
*
*/
public class UserDaoImpl implements UserDao {
//File对象封装文件
private static File file=new File("user.txt");
static{
try {
file.createNewFile();
} catch (IOException e) {
System.out.println("文件创建失败");
}
}
//登录功能
@Override
public boolean isLogin(String username, String password) {
//定义标记
boolean flag=false;
//创建字符输入流
BufferedReader br=null;
try {
br=new BufferedReader(new FileReader(file));
//一次读一行
String line=null;
while((line=br.readLine())!=null){
String[] s = line.split("=");
if(s[0].equals(username) && s[1].equals(password)){
//登录成功,修改标记
flag=true;
}
}
} catch (FileNotFoundException e) {
System.out.println("登录时找不到文件导致失败");
} catch (IOException e) {
System.out.println("用户登录失败");
}finally{
//释放资源
if(br!=null){
try {
br.close();
} catch (IOException e) {
System.out.println("释放资源失败");
}
}
}
return flag;
}
//注册功能
@Override
public void regist(User user) {
//注册使用字符缓冲输出流
BufferedWriter bw=null;
try {
bw=new BufferedWriter(new FileWriter(file ,true));
//固定一种格式
bw.write(user.getUsername()+"="+user.getPassword());
bw.flush();
bw.newLine();
} catch (IOException e) {
System.out.println("用户注册失败");
}finally{
//针对流对象非空判断
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
System.out.println("用户注册释放资源失败");
}
}
}
}
}
用户测试类
package org.westos_11_User;
import java.util.Scanner;
/**
* 用户测试类
* @author 小鑫
*
*/
public class UserTest {
public static void main(String[] args) {
while(true){
//选择界面
System.out.println("--------欢迎光临--------");
System.out.println("1 注册");
System.out.println("2 登录");
System.out.println("3 退出");
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//调用功能
UserDaoImpl ud = new UserDaoImpl();
System.out.println("请选择");
String choice = sc.nextLine();
switch(choice){
case "1":
//注册界面
System.out.println("------注册界面------");
System.out.println("请输入用户名");
String newUsername = sc.nextLine();
System.out.println("请输入密码");
String newPassword = sc.nextLine();
//创建用户对象,封装用户名和密码
User u = new User();
u.setUsername(newUsername);
u.setPassword(newPassword);
//调用东功能
ud.regist(u);
System.out.println("恭喜您,注册成功");
break;
case "2":
//登陆界面
System.out.println("------登陆界面------");
System.out.println("请输入用户名:");
String username = sc.nextLine() ;
System.out.println("请输入密码:");
String password = sc.nextLine() ;
//调用功能
boolean flag = ud.isLogin(username, password);
if(flag){
System.out.println("登录成功");
System.exit(0);
}else{
System.out.println("登录失败,用户名或密码不正确");
}
break;
case "3":
//退出界面
System.out.println("谢谢使用,欢迎下次光临");
System.exit(0);
break;
}
}
}
}