(java多线程)线程的同步(加锁)+Timer定时器

t1和t2两个线程
异步编程模型:t1线程执行t1的,t2执行t2的,
同步编程模型:t1线程和t2线程执行,当t1线程必须等t2线程执行结束之后,t1线程才能执行,这是同步编程模型

什么时候要同步,为什么要引入线程同步呢?
1.为了数据的安全。可以不考虑效率,因为同步机制加入后,效果等同同单线程的

2.什么条件下要使用线程同步?
第一:必须是多线程环境
第二:多线程环境共享同一个数据
第三:共享的数据涉及到修改操作
比如银行取钱的模型,不能异步进行

package 线程的同步;
/*
 * 以下程序演示取款例子。以下程序不使用线程同步机制,
 * 多线程同时对同一个账户进行取款操作,会出现什么问题?
 * 
 * */

public class Test {

	public static void main(String[] args) throws Exception{
		//创建一个公共账户
		Account ac1 = new Account("a1",5000);
		
		//定义两个线程
		Processor p1 = new Processor(ac1);
		Thread t1 = new Thread(p1);
		
		Processor p2 = new Processor(ac1);
		Thread t2 = new Thread(p2);
		
		t1.start();
		//Thread.sleep(5000);
		t2.start();
		
	}

}

//准备线程
class Processor implements Runnable{
	//账户
	Account act;
	
	//构造方法
	Processor(Account act){
		this.act = act;
	}
	public void run() {
		System.out.println("当前余额:"+act.look());
		act.withdraw(100);
		System.out.println("取款成功  余额:"+act.mon);
	}
}

//账户
class Account{
	String name;
	int mon;
	public Account(String name,int mon) {
		this.name = name;
		this.mon = mon;
	}
	
	public void withdraw(int money) {
		mon -=money;
	}
	
	public int look() {
		return mon;
	}
	
}

使用线程同步机制保证数据安全,重写以上程序
关键字:synchronized
方法(){
synchronized(共享对象){
把需要同步的代码放到同步语句块中
}
}

实现的原理:t1线程和t2线程
t1线程执行到此处,遇到了synchronized关键字,就回去找this的对象锁
如果找到this对象锁,则进入同步语句块中执行程序。当同步语句块中的代码执行结束之后,t1线程归还this的对象锁。

在t1线程执行同步语句块的过程中,如果t2线程也过来执行以下代码,也遇到synchronized关键字,所以也去找this的对象锁,但是该对象锁被t1线程持有,只能在这等待this对象的归还

这种方法能够精确的圈定想要同步的代码块

public void withdraw(int money) {
			synchronized(this) {
			mon -=money;
			}  
		}

synchronized放在成员方法上,代表的就是当前对象,当前方法内部所有的代码块都要同步执行

public synchronized void withdraw(int money) {
			
			mon -=money;
		}

一个对象只有一个锁,如果同一个对象下,不同的方法都有synchronized关键字,那么就需要一个方法执行完把锁返回,然后新的方法才能拿锁执行下一个

但是如果同一对象下,没有加上synchronized关键字的方法,不会等待,而是直接执行

类锁

锁是类级别的,一个类只有一个
以及在静态方法上添加synchronized关键字

/*
	类锁,
*/

public class Test3 {

	public static void main(String[] args) throws Exception{
		Thread t1 = new Thread(new process());
		t1.setName("t1");
		Thread t2 = new Thread(new process());
		t2.setName("t2");
		//类锁就一把,在静态方法中使用,一个类中有synchronized 关键字的静态方法,都需要“等”
		
		t2.start();
		t1.start();
		
		
	}

}
class process implements Runnable{
	/*
	 * Myclass ms; process(Myclass ms){ this.ms =ms; }
	 */
	public void run() {
		if(Thread.currentThread().getName().equals("t1"))
		{
			Myclasss.m1();
		}
		else if(Thread.currentThread().getName().equals("t2")) {
			Myclasss.m2();
		}
	}
}

class Myclasss{
	public synchronized static void m1() {
		try {
			Thread.sleep(5000);
		} catch (Exception e) {
			
		}
		System.out.println("m1.....");
	}
	public synchronized static void m2() {
		System.out.println("m2.....");
	}
	
}

死锁

一个死锁的写法

/*死锁*/

public class Test4 {

	public static void main(String[] args) {
		Object o1 = new Object();
		Object o2 = new Object();
		
		Thread t1 = new Thread(new T1(o1,o2));
		Thread t2 = new Thread(new T2(o1,o2));
		
		t1.start();
		t2.start();
		

	}

}
class T1 implements Runnable{
	Object o1;
	Object o2;
	
	T1(Object o1,Object o2){
		this.o1 = o1;
		this.o2 =o2;
	}
	public void run() {
		synchronized (o1) {
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
				// TODO: handle exception
			}
			synchronized (o2) {
				System.out.println("dsds");
			}
		}
	}
}


class T2 implements Runnable{
	Object o1;
	Object o2;
	
	T2(Object o1,Object o2){
		this.o1 = o1;
		this.o2 =o2;
	}

	public void run() {
		synchronized (o2) {
			System.out.println("dsddds");
			synchronized (o1) {
				System.out.println("dsddds");
			}
		}
		
	}
}

守护线程

其他所有的用户线程结束,则守护线程退出!
守护线程一般都是无限执行的
void setDaemon(boolean on) 将一个用户线程转换为守护线程

以下程序可以看出如果不把线程t1转化为守护线程,那么程序将会一直执行下去,可是当将其转化为守护线程后,当主线程(用户线程)执行完毕,守护线程就会结束了

/*守护线程*/

public class Test05 {

	public static void main(String[] args) {
			Thread t1 = new Thread(new Proeceeewesd());
			
			//将t1线程转变为守护线程
			t1.setDaemon(true);
			
			t1.start();
			
			//主线程
			for (int i = 0; i <10; i++) {
				System.out.println(Thread.currentThread().getName()+"--->"+i);
			}

	}

}
class Proeceeewesd implements Runnable
{
	int i=0;
	public void run() {
		while(true)
		{
			i++;
			System.out.println("----->"+i);
		}
		}
	
		}
	

定时器的应用

关于定时器的应用
作用:每隔一段固定的时间执行一段代码

java.util.Timer
Timer类下的成员方法:
从指定 的时间开始 ,对指定的任务执行重复的 固定延迟执行
void schedule(TimerTask task, Date firstTime, long period)

1.TimerTask task 这是要执行的任务代码,同时主要TimerTask是一个抽象类,不能直接实例化对象
java.lang.Object
java.util.TimerTask
TimerTask类中的抽象方法run,是子类一定要实现的,任务代码就在run方法内部去执行

2.Date firstTime 指定任务开始的时间,即到这个时间之后,开始执行定时任务里面的代码
3. long period 每执行一次TimerTask内 任务代码间隔的时间
示例程序

import java.text.SimpleDateFormat;
import java.util.*;
public class TimerTest {

	public static void main(String[] args) throws Exception{
		//创建定时器
		Timer t =new Timer();
		//指定定时任务
		//从指定 的时间开始 ,对指定的任务执行重复的 固定延迟执行 。
		t.schedule(new TimerNewTest(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").parse("2020-03-13 15:03:00 000"), 5*1000);
		
		
	}

}
class TimerNewTest extends TimerTask
{
	public void run() {
		SimpleDateFormat s1 =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
		String f1 = s1.format(new Date());
		System.out.println(f1);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值