Java中线程的实现方式
- 继承Thread类,重写run方法。在run方法中实现具体逻辑
public class ExtendThread {
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
threadTest.start();
}
}
class ThreadTest extends Thread{
@Override
public void run() {
System.out.println(“thread”);
}
} - 实现runnable接口。
public class RunnableTest {
public static void main(String[] args) {
ThreadImRunnable runnable = new ThreadImRunnable();
Thread thread = new Thread(runnable);
thread.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+“main***********”+i);
}
}
}
class ThreadImRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(“我是Runnable”+i);
}
}
}
线程和进程理解
● 只有当所有线程结束,进程才会结束
● start()开启多线程。最终调用jvm的start0(),使该线程处于可运行状态。等待cpu调度。
● 主线程启动子线程的运行。只有当主线程和子线程都结束了。整个进程才会结束。
● 继承Thread和实现Runnable接口的区别。继承Thread类只能线程独享资源。每个Thread都会创建新的资源。实现Runnable接口可以实现多线程共享资源的情况。避免了但继承的限制。
通知线程退出
在实现Runnable接口的或者继承Thread的类里面添加一个属性,并且设置getset方法。在主线程某个时刻修改这个属性。使其停止执行。
public class ThreadExit {
public static void main(String[] args) throws InterruptedException {
ThreadExit_ threadExit_ = new ThreadExit_();
threadExit_.start();
Thread.sleep(5*1000);
//设置为false,满足使其停止循环的条件。退出线程
threadExit_.setLoop(false);
}
}
class ThreadExit_ extends Thread{
private int count = 0;
public void setLoop(boolean loop) {
this.loop = loop;
}
//通知线程终止属性
private boolean loop = true;
@Override
public void run() {
while (loop){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程"+(++count));
}
}
}
线程的礼让和插入
线程礼让:指的是某一个线程礼让另一个线程。但是只是让出竞争资源。实际还要根据cpu调度来看。礼让不一定成功。也有可能两个线程还是同时执行
线程插入:指的是某一个线程执行Thread.join()方法。停止执行当前线程。直到join进来的线程全部执行完毕再执行之前的线程。
public class JoinThread {
public static void main(String[] args) throws InterruptedException {
ThreadJoin threadJoin = new ThreadJoin();
threadJoin.start();
for (int i = 0; i < 20; i++) {
System.out.println(“主线程在吃包子”+i);
Thread.sleep(1000);
if(i==10){
System.out.println(“主线程让子线程插队吃”);
//执行join方法
threadJoin.join();
}
}
}
}
class ThreadJoin extends Thread{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(“子线程在吃包子”+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
用户线程和守护线程
用户线程:也叫工作线程,正常执行完或者以通知方式退出。
守护线程:当所有线程执行完,该线程也会自动退出。
使用实例:垃圾回收机制
public class DeamonThread {
public static void main(String[] args) throws InterruptedException {
T t = new T();
Thread thread = new Thread(t);
//设置为守护线程。注意要在线程启动之前
thread.setDaemon(true);
thread.start();
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.println("俺们在干活");
}
}
}
class T implements Runnable{
@Override
public void run() {
for(;;){
try {
Thread.sleep(1000);
System.out.println("俺们在聊天");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
使用synchronized�买卖售票问题
public class SellThread {
public static void main(String[] args) {
SellTicketThread sellTicketThread01 = new SellTicketThread();
SellTicketThread sellTicketThread02 = new SellTicketThread();
SellTicketThread sellTicketThread03 = new SellTicketThread();
sellTicketThread01.start();
sellTicketThread02.start();
sellTicketThread03.start();
// SellTicketIm sellTicketIm = new SellTicketIm();
// new Thread(sellTicketIm).start();
// new Thread(sellTicketIm).start();
// new Thread(sellTicketIm).start();
}
}
class SellTicketThread extends Thread{
//继承Thread类的方式售票。
//因为每次都是新创建实例开启线程(创建多个实例对象)。要将售卖方法,
// 还有对应变量都要置为静态变量(这样方法和类变量就不受创建实例的数量影响。归类元信息所有)。以供多个线程共享资源。
public static int num = 300;
public static boolean loop = true;
private static synchronized void sell(){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (num<=0){
loop = false;
System.out.println("票卖完了");
return;
}
System.out.println("窗口"+Thread.currentThread().getName()+"售卖了一张票,当前窗口余票为"+(--num));
}
@Override
public void run() {
while (loop){
sell();
}
}
}
class SellTicketIm implements Runnable{
//实现Runnable接口的方式售票。
//实例只创建一次。交由多个线程来跑。这个实例就相当于共享资源,所以不需要将内部变量和方法置为静态类型。
// 只需将售卖方法用synchronized修饰。保证该方法同一时刻只有一个线程可以访问,其他线程为等待状态。
public int num = 1000;
public boolean loop = true;
private synchronized void sell(){
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (num<=0){
loop = false;
System.out.println(“票卖完了”);
return;
}
System.out.println(“窗口”+Thread.currentThread().getName()+“售卖了一张票,当前窗口余票为”+(–num));
}
@Override
public void run() {
while (loop){
sell();
}
}
}
线程常用方法
setName()//使线程名字与传入参数相同
getName()//获取线程名称
sleep()//使当前线程休眠给定毫秒时间。(暂停执行)
start()//使该线程开始执行(准确的说是获得可运行状态。等待cpu调度)。底层jvm调用start0()
run()//调用线程对象run方法
setPriority()//设置线程优先级
getPriority()//获取线程优先级
interrupt()//线程中断
互斥锁
线程之间的争抢只能是同一个引用,如果都是独立的引用则会产生无效的争抢。使用synchronzied修饰代码块或者类进行线程互斥。
实现互斥锁的步骤
- 分析需要上锁的代码
- 选择同步代码块或者同步方法。
- 保证多线程锁对象为同一个即可。即synchronzied(a)。a为多个线程共享资源即可。
- 采用继承Thread类和实现Runnable接口来保证互斥锁的方式不同。(尽量选择同步代码块来保证互斥。)
○ 继承Thread类开启线程要实例化三个实体。每个实体都有自己的属性。最好是把私有属性都用static修饰。
○ 实现Runnable接口只需要中需要synchronzied()修饰的同步代码或者同步方法的位置即可。因为只需要实例化一个实体。非静态同步方法的锁可以是this。也可以是其他对象(要求为同一对象)。静态同步方法的锁是当前类的Class对象。
代码示例
[ ] 继承Thread类非静态代码块
public class SellThread {
public static void main(String[] args) {
SellTicketThread sellTicketThread01 = new SellTicketThread();
SellTicketThread sellTicketThread02 = new SellTicketThread();
SellTicketThread sellTicketThread03 = new SellTicketThread();
sellTicketThread01.start();
sellTicketThread02.start();
sellTicketThread03.start();
// SellTicketIm sellTicketIm = new SellTicketIm();
// new Thread(sellTicketIm).start();
// new Thread(sellTicketIm).start();
// new Thread(sellTicketIm).start();
}
}
class SellTicketThread extends Thread{
//继承Thread类的方式售票。
//因为每次都是新创建实例开启线程(创建多个实例对象)。要将售卖方法,
// 还有对应变量最好置为静态变量(这样方法和类变量就不受创建实例的数量影响。归类元信息所有)。以供多个线程共享资源。
public static int num = 100;
public static boolean loop = true;
private void sell(){
//这里如果用this则会出现超卖或重复卖现象。synchronized修饰静态代码块
//使用SellTicketThread.class是为了获取类元信息。使多个线程共享这一个资源。进行锁竞争。形成互斥锁。
synchronized(SellTicketThread.class){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (num<=0){
loop = false;
System.out.println("票卖完了");
return;
}
System.out.println("窗口"+Thread.currentThread().getName()+"售卖了一张票,当前窗口余票为"+(--num));
}
}
@Override
public void run() {
while (loop){
sell();
}
}
}
[ ] 继承Thread类非静态方法(普通方法)
public class SellThread {
public static void main(String[] args) {
SellTicketThread sellTicketThread01 = new SellTicketThread();
SellTicketThread sellTicketThread02 = new SellTicketThread();
SellTicketThread sellTicketThread03 = new SellTicketThread();
sellTicketThread01.start();
sellTicketThread02.start();
sellTicketThread03.start();
// SellTicketIm sellTicketIm = new SellTicketIm();
// new Thread(sellTicketIm).start();
// new Thread(sellTicketIm).start();
// new Thread(sellTicketIm).start();
}
}
class SellTicketThread extends Thread{
//继承Thread类的方式售票。
//因为每次都是新创建实例开启线程(创建多个实例对象)。要将售卖方法,
// 还有对应变量都要置为静态变量(这样方法和类变量就不受创建实例的数量影响。归类元信息所有)。以供多个线程共享资源。
public static int num = 100;
public static boolean loop = true;
private synchronized void sell(){
//synchronized修饰普通方法
//使用SellTicketThread.class是为了获取类元信息。使多个线程共享这一个资源。进行锁竞争。形成互斥锁。
// synchronized(SellTicketThread.class){
//
// }
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (num<=0){
loop = false;
System.out.println(“票卖完了”);
return;
}
System.out.println(“窗口”+Thread.currentThread().getName()+“售卖了一张票,当前窗口余票为”+(–num));
}
@Override
public void run() {
while (loop){
sell();
}
}
}
[ ] 静态方法
public class SellThread {
public static void main(String[] args) {
// SellTicketThread sellTicketThread01 = new SellTicketThread();
// SellTicketThread sellTicketThread02 = new SellTicketThread();
// SellTicketThread sellTicketThread03 = new SellTicketThread();
// sellTicketThread01.start();
// sellTicketThread02.start();
// sellTicketThread03.start();
SellTicketIm sellTicketIm = new SellTicketIm();
new Thread(sellTicketIm).start();
new Thread(sellTicketIm).start();
new Thread(sellTicketIm).start();
}
}
class SellTicketIm implements Runnable{
//实现Runnable接口的方式售票。
//实例只创建一次。交由多个线程来跑。这个实例就相当于共享资源,所以不需要将内部变量和方法置为静态类型。
// 只需将sell()用synchronized修饰。保证该方法同一时刻只有一个线程可以访问,其他线程为等待状态。
public int num = 100;
public boolean loop = true;
private synchronized static void sell(){
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (num<=0){
loop = false;
System.out.println(“票卖完了”);
return;
}
System.out.println(“窗口”+Thread.currentThread().getName()+“售卖了一张票,当前窗口余票为”+(–num));
}