线程是程序的一条执行线索,执行路径,是程序使用cpu的最小单位,其实说白了,线程是指进程中的一个执行流程,一个进程中可以运行多个线程,那java线程怎么做标记?下面来我们就来给大家讲解一下。
代码如下:
/*
停止线程:
1 stop 方法。
2 run 方法结束
怎么控制线程的任务结束?
任务中都会有循环结构(没有循环就不需要多线程了,开多线程就是怕这里循环影响其他),只要控制住循环就可以结束任务
控制循环通常就用定义标记来完成
*/
class StopThread implements Runnable
{
private boolean flag = true;
public void run()
{
while (flag)
{
System.out.println(Thread.currentThread()
.getName() + "....");
}
}
public void setFlag()
{
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 = 1;
for (;;)
{
if (++num == 50)
{
st.setFlag(); //此处将标记变为false 停止线程
break;
}
System.out.println("main..." + num);
}
}
}java线程如何同步?
语法:
synchronized(锁对象)
{
同步代码块
}工作原理:
线程要执行同步代码块,必须先获得锁对象;
任意对象都可以作为锁对象, 任意对象都有一个内置锁;
一个锁对象最多被一个线程持有;
线程持有了锁对象后,会一直持有, 直到执行完同步代码块后才会释放锁对象;
package com.wkcto.chapter07.sync.p2;
/**
* 银行帐户类
* @author 蛙课网
*
*/
public class BankAccount
{
int balance = 10000; //余额 ,单位:万元
private static final Object OBJ = new Object(); //常量
//取钱的操作, 约定, 每次取钱1000
public void withdraw()
{
synchronized(OBJ)
{ //一般使用常量作为锁对象
System.out.println(Thread.currentThread()
.getName() + "取钱 前, 余额为:" + balance);
balance -= 1000;
System.out.println(Thread.currentThread()
.getName() + "取了1000万后, 余额为:" + balance);
}
/*
* 1) xiaoming获得了CPU执行权, 执行withdraw()方法, 先获得OBJ锁对象, 执行同步代码块
* 2) xiaoming在执行同步代码块期间, CPU执行权被baby抢走了, xiaoming转为就绪状态
* babay获得CPU执行权, 要也执行同步代码块, 必须先获得OBJ锁对象,
* 现在OBJ锁对象被xiaoming持有, baby线程转到等待锁对象池中阻塞
* 3) xiaoming重新获得CPU执行权, 继续执行同步代码块, 执行完同步代码块后, 释放OBJ锁对象
* 4) 等待锁对象池中的baby如果获得了锁对象, 转为就绪状态
*/
}
}package com.wkcto.chapter07.sync.p2;
/**
* 定义一个线程类,模拟 从银行帐户 中取钱
* @author 蛙课网
*
*/
public class PersonThread extends Thread
{
private BankAccount bankaccount; //银行帐户
public PersonThread(BankAccount bankaccount)
{
super();
this.bankaccount = bankaccount;
}
@Override
public void run()
{
bankaccount.withdraw();
}
}package com.wkcto.chapter07.sync.p2;
/**
* 使用线程模拟多人同时从某一帐户中取钱
* 线程同步
* @author 蛙课网
*
*/
public class Test01
{
public static void main(String[] args)
{
//先开户
BankAccount account = new BankAccount();
//定义三个线程模拟三个人, 是从同一个帐户中取钱
PersonThread xiaoming = new PersonThread(account);
PersonThread bingbing = new PersonThread(account);
PersonThread baby = new PersonThread(account);
xiaoming.setName("xiaoming");
bingbing.setName("bingbing");
baby.setName("baby");
xiaoming.start();
bingbing.start();
baby.start();
}
}同步代码块
同步代码块要想实现同步,必须保证使用同一个锁对象
只要使用了同一个锁对象的同步代码块就可以同步
package com.wkcto.chapter07.sync.p3;
/**
* 同步代码块, 只要使用相同的锁对象就可以实现同步
* @author 蛙课网
*
*/
public class Test01
{
public static void main(String[] args)
{
PrintNum pNum = new PrintNum();
//创建线程,调用m1()
new Thread(new Runnable()
{
@Override
public void run()
{
pNum.m1();
}
})
.start();
//创建线程,调用m2()
new Thread(new Runnable()
{
@Override
public void run()
{
//pNum.m2();//当使用this对象作为锁对象时, 可以同步
new PrintNum()
.m2(); //使用this作为锁对象, 不能同步, 与第一个线程的锁对象不是一个
}
})
.start();
}
}package com.wkcto.chapter07.sync.p3;
/**
* 定义类
* 提供两个 方法,分别打印字符串
* @author 蛙课网
*
*/
public class PrintNum
{
private static final Object OBJ = new Object(); //定义常量
public void m1()
{
//synchronized (OBJ) {//经常使用常量作为锁对象
synchronized(this)
{ //有时也会使用this作为锁对象 , 就是调用m1()方法的对象
for (int i = 1; i <= 200; i++)
{
System.out.println("wkcto is NB website");
}
}
}
public void m2()
{
//synchronized (OBJ) {
synchronized(this)
{
for (int i = 1; i <= 200; i++)
{
System.out.println("bjpowernode is a good school");
}
}
}
}ackage com.wkcto.chapter07.sync.p4;
/**
* 使用当前类的运行时类作为锁对象
* @author 蛙课网
*
*/
public class Test02
{
public static void main(String[] args)
{
//创建线程, 打印wkcto
new Thread(new Runnable()
{
@Override
public void run()
{
while (true)
{
printText("wkcto");
}
}
})
.start();
//创建线程, 打印bjpowernode
new Thread(new Runnable()
{
@Override
public void run()
{
while (true)
{
printText("bjpowernode");
}
}
})
.start();
}
private static final Object OBJ = new Object(); //常量
//静态方法,打印一个字符串
public static void printText(String text)
{
//synchronized (OBJ) {
synchronized(Test02.class)
{ //使用当前类的运行时类对象作为锁对象, 有人把它称为类锁
//可以简单的理解 为把当前类的字节码文件作为锁对象
for (int i = 0; i < text.length(); i++)
{
System.out.print(text.charAt(i));
}
System.out.println();
}
}
}同步方法
package com.wkcto.chapter07.sync.p5;
/**
* 同步实例方法, 就是把整个方法体作为同步代码块, 默认锁对象 是this对象
*/
public class Test01
{
public static void main(String[] args)
{
Test01 obj = new Test01();
//创建线程, 调用m1()
new Thread(new Runnable()
{
@Override
public void run()
{
obj.m1();
}
})
.start();
//创建线程, 调用m2()
new Thread(new Runnable()
{
@Override
public void run()
{
obj.m2();
}
})
.start();
}
/*
* 把整个方法体作为同步代码块,并且使用this作为锁对象时, 可以直接使用synchronized修饰方法, 称为同步方法
* 同步实例方法, 就是把整个方法体作为同步代码块, 默认锁对象 是this对象
*/
public synchronized void m1()
{
for (int i = 1; i <= 500; i++)
{
System.out.println(Thread.currentThread()
.getName() + "-->" + i);
}
}
public void m2()
{
synchronized(this)
{
for (int i = 1; i <= 500; i++)
{
System.out.println(Thread.currentThread()
.getName() + "======>" + i);
}
}
}
}package com.wkcto.chapter07.sync.p5;
/**
* 同步静态方法, 就是把整个方法体作为同步代码块, 默认锁对象 是当前类的运行时类对象
*/
public class Test02
{
public static void main(String[] args)
{
//创建线程, 调用m1()
new Thread(new Runnable()
{
@Override
public void run()
{
Test02.m1();
}
})
.start();
//创建线程, 调用m2()
new Thread(new Runnable()
{
@Override
public void run()
{
Test02.m2();
}
})
.start();
}
/*
* 把整个方法体作为同步代码块,并且使用当前类的运行时类对象(Test02.class)作为锁对象时, 可以直接使用synchronized修饰方法, 称为同步方法
* 同步静态方法, 就是把整个方法体作为同步代码块, 默认锁对象 是当前类的运行时类对象(Test02.class)
*/
public synchronized static void m1()
{
for (int i = 1; i <= 500; i++)
{
System.out.println(Thread.currentThread()
.getName() + "-->" + i);
}
}
public static void m2()
{
synchronized(Test02.class)
{
for (int i = 1; i <= 500; i++)
{
System.out.println(Thread.currentThread()
.getName() + "======>" + i);
}
}
}
}线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏,所以对于同步,要时刻清醒在哪个对象上同步,这是关键!最后大家如果想要了解更多java入门知识,敬请关注奇Q工具网。
推荐阅读: