.
---------------------- ASP.Net+Android+IOS开发、 .Net培训、期待与您交流! ----------------------静态同步函数的锁是Class对象
如果同步函数被静态修饰后,使用的锁是什么呢?
通过实例11可以发现,不是this了,因为静态方法中不能定义this。
静态进内存时,内存中没有本类对象,但是一定有该类的字节码文件对象:类名.class
该对象的类型是class
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class
flag标记的作用:
做一个标记flag,初始化true,
单独设计同步函数,在同步代码块中调用同步函数,如果一个线程进来,结束后将标记该为false,
那么当另一个线程进来时flag语句为false了,就直接调用同步函数了。
class Ticket implements Runnable{
private static int tick = 100;
boolean flag = true;
public void run(){
if(flag){
while(true){
synchronized(Ticket.class){
if(tick>0){
try{Thread.sleep(10);}catch(Exception e){}
String aa = Thread.currentThread().getName();
System.out.println(aa+".."+tick--);
}
}
}
}
else
while(true)
show();
}
public static synchronized void show(){
if(tick>0){
try{Thread.sleep(10);}catch(Exception e){}
String aa = Thread.currentThread().getName();
System.out.println(aa+"....."+tick--);
}
}
}
class StaticMethoodDemo{
public static void main(String[] args){
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}
t.flag = false;
t2.start();
}
}
死锁
死锁:同步中嵌套同步。
class Ticket implements Runnable{ //创建类实现Runnable接口
private int tick = 10000;
Object obj = new Object();
boolean flag = true; //标记,初始化为true
public void run(){ //复写Runnable的run方法
if(flag){ //如果标记为true,执行同步代码块
while(true){
synchronized(obj){ //加同步代码块,形成嵌套同步--死锁
show(); //调用同步函数show
}
}
}
else //否则执行同步函数
while(true)
show();
}
public synchronized void show(){//同步函数
synchronized(obj){ //同步代码块
if(tick>0){
try{Thread.sleep(1);}catch(Exception e){}
String aa = Thread.currentThread().getName();
System.out.println(aa+".."+tick--);
}
}
}
}
class DeadLockDemo{
public static void main(String[] args){
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}
t.flag = false;
t2.start();
}
}
线程的四种状态
sleep方法需要指定睡眠时间,单位是毫秒。 一个特殊的状态:就绪。具备了执行资格,但是还没有获取资源。
wait(),sleep()有什么区别?
Wait():释放cpu执行权,释放锁。
sleep():释放cpu执行权,不释放锁
线程间通信
class Res{
String name;
String sex;
boolean flag = false; //标记默认为false
}
class Input implements Runnable{
private Res r;
Input(Res r){this.r = r;}
public void run(){
int x = 0;
while(true){
synchronized(r){
if(r.flag) //如果标记为真true
try{r.wait();}catch (Exception e){}
if(x==0){
r.name="maik";
r.sex="man";
}
else{
r.name="小丽";
r.sex="女";
}
x = (x+1)%2;
r.flag = true; //把标记设置为true
r.notify(); //唤醒Output
}
}
}
}
class Output implements Runnable{
private Res r;
Output(Res r){this.r = r;}
public void run(){
while(true){
synchronized(r){
if(!r.flag) //非false就是true
try{r.wait();}catch (Exception e){}//如果标记为true就等待,并放弃执行权
System.out.println(r.name+"..."+r.sex);
r.flag = false;
r.notify();
}
}
}
}
class InputOutputDemo{
public static void main(String[] args){
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}代码优化后
class Res{
private String name;
private String sex;
private boolean flag = false;
//成员变量私有后要提供公有方法来让外界进行设置,此代码必须同步
public synchronized void set(String name,String sex){
//如果标记为true,就让线程等待。
if(flag)
try{this.wait();}catch (Exception e){}
//设置后,将标记设置为true并唤醒被等待的线程。
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
//输出方法
public synchronized void out(){
//如果标记为true,就让线程等待。
if(!flag)
try{this.wait();}catch (Exception e){}
//输出后,将标记设置为false并唤醒被等待的线程。
System.out.println(name+"--"+sex);
flag = false;
this.notify();
}
}
//输入类
class Input implements Runnable{
private Res r;
Input(Res r){
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x==0)
r.set("小强","男");
else
r.set("小丽","女");
//保证条件x变量在0和1之间交替
x = (x+1)%2;
}
}
}
//输出类
class Output implements Runnable{
private Res r;
Output(Res r){
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
class InputOutputDemo{
public static void main(String[] args){
Res r = new Res();//资源
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}
停止线程
stop方法已经过时
如何停止线程?
只有一种方法,run方法结束。开启多线线程,运行代码通常是循环结构。
只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:
当线程处于冻结状态,就不会读取到标记,那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
Thread类提供该方法 interrupt();
class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag){
try{
wait();
}
catch(InterruptedException e){
System.out.println(Thread.currentThread().getName()+"....Exception");
flag = false;
}
System.out.println(Thread.currentThread().getName()+"....run");
}
}
public void changeFlag(){
flag = false;
}
}
class StopThreadDemo{
public static void main(String[] args){
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num = 0;
while(true){
if(num++ ==60){
//st.changeFlag();
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"...."+num);
}
System.out.println("over");
}
}
守护线程
守护线程 setDaemon
特点:开启后和前台线程共同抢劫CPU的执行权运行
public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。
该方法首先调用该线程的 checkAccess 方法,且不带任何参数。这可能抛出 SecurityException(在当前线程中)。
class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag){
try{
wait();
}
catch(InterruptedException e){
System.out.println(Thread.currentThread().getName()+"....Exception");
flag = false;
}
System.out.println(Thread.currentThread().getName()+"....run");
}
}
public void changeFlag(){
flag = false;
}
}
class StopThreadDemo{
public static void main(String[] args){
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
//守护/用户线程,也可以说是后台线程。
//他的特点:开启后和前台线程共同抢劫CPU的执行权运行
t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();
int num = 0;
while(true){
if(num++ ==60){
//t1.interrupt();
//t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"...."+num);
}
System.out.println("over");
}
}
Join方法
public final void join()
throws InterruptedException等待该线程终止。
当A线程执行到了B线程的join()方法时,A就会等待,等B线程都执行完后,A线程才执行。
join可以用来临时加入线程执行。
class Demo implements Runnable{
public void run(){
for (int x=0;x<=10 ;x++ ){
System.out.println(Thread.currentThread().getName()+"...."+x);
}
}
}
class JoinDemo{
public static void main(String[] arsg) throws Exception{
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
//t1通过join方法抢夺CPU执行权,t1获得执行权后主线程被冻结。
//t1执行run()结束后,主线程才继续执行。
t1.join();
t2.start();
for (int x=0;x<=10 ;x++ ){
System.out.println("main...."+x);
}
System.out.println("over");
}
}
线程优先级
yield() 暂停当前正在执行的线程对象,并执行其他线程。
setPriority(int newPriority) 更改线程的优先级。newPriority用1-10表示
java已经给出了常用的三个等级:
MAX_PRIORITY 线程可以具有的最高优先级。最高是10
MIN_PRIORITY 线程可以具有的最低优先级。最低是1
NORM_PRIORITY 分配给线程的默认优先级。默认是5
toString():
返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
class Demo implements Runnable{
public void run(){
for (int x=0;x<=5 ;x++ ){
System.out.println(Thread.currentThread().toString()+"...."+x);
}
}
}
class JoinDemo{
public static void main(String[] arsg) throws Exception{
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
//提高t1的优先级频率,但不一定t1先执行。
//t1.setPriority(10);这么写降低了阅读性,应该如下写:
t1.setPriority(Thread.MAX_PRIORITY);
t2.start();
for (int x=0;x<=5 ;x++ ){
System.out.println("main...."+x);
}
}
}
本文详细探讨了Java中线程的多种状态、同步机制、死锁现象及其避免方法,同时介绍了线程间的通信技巧、优先级设定及如何正确地停止线程。
1036

被折叠的 条评论
为什么被折叠?



