线程
package FUXI;
public class Thread_FX {
/**
* 程序:静态的
* 进程:应用程序运行加载到内存中就等于开启了一个进程
* 线程:一条应用程序到CPU的执行路径,CPU通过该路径执行功能
* 主线程:执行主(main)方法的线程
*/
/**
* 创建线程Thread类
* 三种创建方法:Thread子类,Runnable实现类,匿名类
*
*/
/**
* 线程安全问题
* 共享数据
*/
/**
* 线程的状态
* 线程的生命周期,start开始运行,run函数结束了线程就结束了
* 线程结束了,对象还在
*/
public static void main(String[] args) {
Thread1 t=new Thread1();
t.start();
for(int i=0;i<3;i++)
System.out.println(Thread.currentThread().getName()+"---------------------"+i);
Runnable p=new Thread2();
Thread t2=new Thread(p);
t2.setName("王圆圆");
t2.start();
(new Thread1()).start();
(new Thread1()).start();
(new Thread1()).start();
/**
* Thread 常用的方法
* 一.获取线程的名称:
* ①.getName()
* ②通过Thread的静态方法先获取当前正在执行的线程(自然该语句打印了说明该语句执行了说明当前执行的线程就是该语句所在线程),使用线程中的getName获取线程的名称
*
*二.设置名称
*void SetName(String name)
*
*三.sleep
*public static void sleep(long mills)
*使得当前正在执行的线程以指定毫秒数暂停
*
*
*/
//System.out.println(t.getName()+"----------------------");
System.out.println(Thread.currentThread().getName()+"---------------------");
/**
* 创造线程的方法三:
* 使用匿名内部类
*/
new Thread() {
public void run() {
for(int i=0;i<3;i++)
System.out.println(Thread.currentThread().getName()+"---------------------"+i);
}
}.start();;
Thread tt=new Thread() {
public void run() {
for(int i=0;i<3;i++)
System.out.println(Thread.currentThread().getName()+"---------------------"+i);
}
};
tt.start();
Runnable a=new Runnable() {
public void run() {
for(int i=0;i<3;i++)
System.out.println(Thread.currentThread().getName()+"---------------------"+i);
}
};
Thread t3=new Thread(a);
t3.start();
new Thread(new Runnable() {
public void run() {
for(int i=0;i<3;i++)
System.out.println(Thread.currentThread().getName()+"---------------------"+i);
}
}).start();
}}
/**
* 创建线程的方法一:
* 1.创建一个Thread类的子类
* 2.在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么)
* 3.创建Thread类的子类对象
* 4.调用Thread类中的方法start方法,开启新的线程,执行run方法
* 注意:调用start而不是直接调用run方法
* 不能多次启动同一个线程,这是非法的。特别是当线程已经执行结束后,不能再重新启动。
*/
class Thread1 extends Thread{
public void run() {
for(int i=0;i<3;i++)
System.out.println(Thread.currentThread().getName()+"---------------------"+i);
}
}
/**
* 创建线程的方法二:
* 避免了单继承的局限性,降低了程序的耦合性,将设置线程任务和开启新的线程分开了
* 1.创建一个Runnable的实现类
* 2.重写Runnable的run方法,设置执行任务
* 3.创建Runnable实现类对象
* 4.创建Thread对象,有参构造,传递Runnable实现类对象
* 5.调用start方法,开启新的线程,执行run方法
*
*/
class Thread2 implements Runnable{
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0;i<3;i++)
System.out.println(Thread.currentThread().getName()+"---------------------"+i);
}
}
卖票案例
会出现重票,错票
package FUXI;
/**
* 三个线程同步进行,
* 可能发生两个线程已经进入循环,失去CPU的执行权,另一个线程进入循环,改变了ticket,使得ticket不再满足循环要求,但是另外两个线程已经进入了循环,再接着执行循环体,改变ticket,则出现了负票
* 重票是由于还没执行ticket--时,另一个程序执行了输出语句
* @author ann
*
*/
/**
* 解决卖票出现重票,错票的线程安全问题的想法:
* 使用共享数据时,只允许一个线程进行(单线程)其他线程只能等待,等待当前线程处理完共享数据,才能执行
* @author ann
*
*/
public class Ticket_FX {
public static void main(String[] args) {
Runnable a=new T();
new Thread(a).start();
new Thread(a).start();
new Thread(a).start();
}
}
class T implements Runnable{
private int ticket=100;
public void run() {
while(true) {
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"几张票");
ticket--;
}
}
}
}
解决线程安全问题
package FUXI;
/**
* 解决卖票案例中出现卖出不存在的票和卖出重复的票
* 解决方案一:同步代码块
* 1.操作共享数据的代码即为需要被同步的代码
* 共享数据:多个线程共同操作的变量
* Thread子类的共享数据static
* Runnable的共享数据为多个Thread对象使用同一个Runnable实现类对象构造可能会使用相同的数据
* 2.同步锁
* 锁:任何一个类的对象都可以充当锁
* 要求:多个线程必须共用同一把锁
* 注意Thread子类和Runnable实现类的区别,用new的对象做锁的话,要是Thread子类的锁一样,需要给锁对象家static,Runnable实现类不需要
*
* 简便Runnable实现可以用this做锁,Thread实现类不能用this,当前对象是不一样的,下面案例this就有三个,可以用类对象:Thread实现类名.class
*
* 使用同步代码块,格式:
* synchronized(锁对象){
* 可能出现线程安全问题的代码(访问了共享数据的代码)//需要被同步的代码
*
* }
*注意:1.锁对象可以是任意类型的对象
* 2.必须保证多个线程使用的锁对象是同一个!!!!!
* 3.锁对象的作用:把同步代码块锁住,只让一个线程在同步代码块中执行
*
*解决方案二: 同步方法
*使用同步方法:使用步骤
*1.把访问了共享数据的代码抽取出来,放在一个方法中
*2.在方法上添加synchronized
*
*格式:定义方法的格式
*修饰符 synchronized 返回值类型 方法名(参数列表)
*
*Runnable实现类的同步方法为非静态的可以,(锁实际上就是this)
*但是Thread实现类的同步方法为非静态的不可以(锁是对象this,有三个)
*Thread实现类的同步方法需要使用静态的,这样能将共享数据同步,(这个锁就是Thread子类.class)
*注意:同步方法仍然涉及同步监视器,只是不需要我们显式声明
*非静态的同步方法同步监视器是this
*静态的同步方法监视器是当前类本身
*
*/
/**
* 以下只是用Runnable实现类为例,Thread子类情况有些许不同
*
*/
public class Ticket_solve_FX {
public static void main(String[] args) {
Runnable a=new TS();
new Thread(a).start();
new Thread(a).start();
new Thread(a).start();
}
}
class TS implements Runnable{
private int ticket=100;
Object obj=new Object(); //保证多个线程使用的锁对象是同一个
public void run() {
while(true) {
//锁对象实际上就是这里Runnable实现类对象,this
//静态的同步的锁对象不是this,是本类的class属性
// synchronized(obj) {
// if(ticket>0) {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"几张票");
// ticket--;
// }
//
payTicket();
}
}
public synchronized void payTicket() {
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"几张票");
ticket--;
}
}
}
题目
选课系统
选课投票。某学生不确定自己应该选择“数学物理方程”还是“Java 程序设计”,决
定交由程序决定,该程序启动两个线程,每个线程在一个随机时间间隔(1-3 秒之间)分别
打印一个课程名称(一个打印“数学物理方程”,一个打印“Java 程序设计”)。两个线程
各执行 大约15 秒后停止,并输出打印的次数,哪个次数多就选择哪个课程
package FUXI;
import java.util.Date;
public class Work5_Thread_XK_FX {
public static void main(String[] args) throws InterruptedException {
output t1=new output();
output t2=new output();
t1.setName("数学物理方程");
t2.setName("java程序设计");
t1.start();
t2.start();
while(t1.running||t2.running) {
Thread.sleep(1000);
}
System.out.println(t1.count+","+t2.count);
System.out.println("----------------");
if(t1.count>t2.count) //线程结束了,对象还是在的
System.out.println("数学物理方程");
else
System.out.println("java程序设计");
}
}
class output extends Thread{
public int count=0;
boolean running=true;
public void run() {
Date s=new Date();
while(true) {
System.out.println(Thread.currentThread().getName());
count++;
try {
Thread.sleep((long) (1000*Math.random()));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Date end=new Date();
if(end.getTime()-s.getTime()>15000)
{running=false;
return;
}
}
}
}