火车站售票案例(1.0.0)
public class Demo01Thread {
//三个窗口售票问题 (没有加同步代码块),用的继承
public static void main(String[] args) {
Sale s1 = new Sale("窗口一");
Sale s2 = new Sale("***窗口二***");
Sale s3 = new Sale("-----窗口三-----");
s1.start();
s2.start();
s3.start();
}
}
class Sale extends Thread{
private static int tickets = 100;
public Sale(String name) {
super(name);
}
public void run() {
while(true) {
if(tickets > 0) {
System.out.println(Thread.currentThread().getName()+"正在卖第" + (tickets--)+"票");
/* System.out.println(Thread.currentThread().getName()+"正在卖第" + (tickets--)+"票");
* 比如说,当线程一执行到"正在卖第"时,CPU被抢占了,那么整句话都不会打印出来.
* 但是需要打印输出的字符串已经存到一个字符串变量里面,
* 存储在缓存中,tickets也已经做了--的操作.等线程一获取到CPU,就会打印存储在缓存中的这个字符串!
* 所以会出现
***窗口二***正在卖第99票
-----窗口三-----正在卖第98票
窗口一正在卖第100票
***窗口二***正在卖第97票
-----窗口三-----正在卖第97票
这些情况
所以需要同步代码块,上锁去解决这些问题
* */
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
break;
}
}
}
}
练习:
获取主方法以及垃圾回收线程所在的线程名称
public class Demo02Thread {
/*5.练习
获取主方法所在的线程名称--->main
获取垃圾回收线程的线程名称-->Finalizer*/
public static void main(String[] args) {
for(int i = 0; i <= 10;i++) {
new Test();
System.out.println(Thread.currentThread().getName());
System.gc();//手动回收无用对象
}
}
}
class Test{
protected void finalize() throws Throwable{//gc线程回收时,一定会执行的方法
//所有的对象都具有的方法
System.out.println(Thread.currentThread().getName());
}
}
守护线程:
void | setDaemon(boolean on) 将此线程标记为 daemon线程或用户线程。 |
(on=true时,此线程为守护线程)
public class Demo03Thread {
public static void main(String[] args) {
Thread t1 = new Thread(){
public void run() {
for(int n = 1; n < 1000;n++) {
System.out.println(Thread.currentThread().getName()+"............"+n);
}
}
};
t1.setDaemon(true);
t1.start();
for(int n = 1; n < 100; n++) {
System.out.println("main-----" + n);
}
}
}
线程的优先级
通过某些方法,设定当前的线程的优先级,优先级高的线程先运行,优先级低的线程后运行,优先级越高的线程抢到CPU执行权概率更大一些,有可能优先级高的线程先执行完毕。
void | setPriority(int newPriority) 更改此线程的优先级。 |
数字范围:最小1,最大10,默认状态就是5.
static int | 线程可以拥有的最大优先级。 10 |
static int | 线程可以拥有的最小优先级。 1 |
static int | 分配给线程的默认优先级。 5 |
public class Demo04Thread {
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
for(int n = 1; n <= 200;n++) {
System.out.println(Thread.currentThread().getName()+"*******"+n);
}
}
};
t1.setPriority(Thread.MIN_PRIORITY);
Thread t2 = new Thread() {
public void run() {
for(int n = 1; n <= 200;n++) {
System.out.println(Thread.currentThread().getName()+"---*--------"+n);
}
}
};
t2.setPriority(Thread.MAX_PRIORITY);
Thread t3 = new Thread() {
public void run() {
for(int n = 1; n <= 200;n++) {
System.out.println(Thread.currentThread().getName()+"---"+n);
}
}
};
t3.setPriority(Thread.NORM_PRIORITY);
t1.start();
t2.start();
t3.start();
}
}
同步方法:
如果在某个方法中,所有的代码都需要加同步代码块,使用同步方法这种简写格式来替代同步代码块
权限修饰符【静态修饰符】 synchronized 返回值类型 方法名(){}
如果非静态的同步方法默认的锁对象是this
如果是静态方法,同步方法的锁对象就是当前类的字节码对象,类名.class,哪个类在调用这个同步方法,这个同步方法使用锁就是哪个类的字节码对象。
火车站售票案例(2.0.0)
//三个窗口售票问题 (加同步代码块),用的接口
public class Demo05Thread {
public static void main(String[] args) {
SaleTickets st = new SaleTickets();
Thread t1 = new Thread(st,"窗口一******");
Thread t2 = new Thread(st,"窗口二--***");
Thread t3 = new Thread(st,"窗口三*-------");
t1.start();
t2.start();
t3.start();
}
}
class SaleTickets implements Runnable{
private int tickets = 100;
//每个对象共用同一个接口实现类里面的代码,所以这个tickets可以不用定义为static
//但如果是继承,必须加static
@Override
public void run() {
while(true) {
synchronized(this) {
if(tickets>0) {
System.out.println(Thread.currentThread().getName()+"正在卖第"+(tickets--)+"张票");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
火车站售票案例(2.0.0)
//火车站售票案例(加同步代码块),用的匿名内部类
public class Demo06Thread {
private static int tickets = 100;
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
while(true) {
synchronized("lock") {
if(tickets>0) {
System.out.println(Thread.currentThread().getName()+"正在卖第"+(tickets--)+"张票");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
break;
}
}
}
}
},"窗口一********");
Thread t2 = new Thread(new Runnable() {
public void run() {
while(true) {
synchronized("lock") {
if(tickets>0) {
System.out.println(Thread.currentThread().getName()+"正在卖第"+(tickets--)+"张票");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
break;
}
}
}
}
},"窗口二***------");
Thread t3 = new Thread(new Runnable() {
public void run() {
while(true) {
synchronized("lock") {
if(tickets>0) {
System.out.println(Thread.currentThread().getName()+"正在卖第"+(tickets--)+"张票");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
break;
}
}
}
}
},"窗口三-------");
t1.start();
t2.start();
t3.start();
}
}
作业
1、有一辆班车除司机外只能承载80个人,假设前中后三个车门都能上车,如果坐满则不能再上车。
请用线程模拟上车过程并且在控制台打印出是从哪个车门上车以及剩下的座位数。
比如:
(前门上车---还剩N个座...)
public class Homework01 {
/*1、有一辆班车除司机外只能承载80个人,假设前中后三个车门都能上车,如果坐满则不能再上车。
请用线程模拟上车过程并且在控制台打印出是从哪个车门上车以及剩下的座位数。
比如:
(前门上车---还剩N个座...)*/
public static void main(String[] args) {
GetOn go = new GetOn();
Thread t1 = new Thread(go,"前门");
Thread t2 = new Thread(go,"中门");
Thread t3 = new Thread(go,"后门");
t1.start();
t2.start();
t3.start();
}
}
class GetOn implements Runnable{//定义一个上车的类,实现Runnable接口
private int seatCount = 80;
public void run() {
while(true) {
synchronized(this) {
if(seatCount > 0) {
System.out.println((Thread.currentThread().getName() +"上车---还剩"+(--seatCount) +"个座..."));
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
2、同时开启3个线程,共同输出100~200之间的所有数字,并且在输出奇数的时候将线程名称打印出来
public class Homework02 {
/*2、同时开启3个线程,共同输出100~200之间的所有数字,并且在输出奇数的时候将线程名称打印出来*/
public static void main(String[] args) {
PrintNumber pn = new PrintNumber();
Thread t1 = new Thread(pn,"****线程一****");
Thread t2 = new Thread(pn,"*---线程二---*");
Thread t3 = new Thread(pn,"**--线程三--**");
t1.start();
t2.start();
t3.start();
}
}
class PrintNumber implements Runnable{
private int n = 100;
public void run() {
while(n < 200) {
synchronized(this) {
if(n>200) {
break;
}else {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(n % 2 == 1) {
System.out.println(n++);
}else {
System.out.println(Thread.currentThread().getName() + (n++));
}
}
}
}
}