`
段箭*残箫
  • 浏览: 53873 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类

线程知识

阅读更多

1线程:是进程内部运行的一个顺序控制流,是有别于进程的,它是在进程内部运行的,一个进程可能包含多个线程,线程是共享内存地址空间,而一个进程是独占内存地址空间。

2.如何实现多线程

方式1.继承Thread类(实际上Thread也是实现了Runnable接口的,并实现了run()方法)

方式2.实现Runnable接口

以上两种都可以实现多线程,但是都必须重写run()方法,而且启动线程是调用start()方法,而不是run()方法;如果调用run()方法启动线程,只是调用了一个普通的方法而已,并没有产生新的线程。

注意:以上两种方式实现多线程时,只能调用一次start()方法,同一个线程如果重复调用start()方法,会抛出一个异常,这得从Thread的源码中分析:

 public synchronized void start() {
        /**
	 * This method is not invoked for the main method thread or "system"
	 * group threads created/set up by the VM. Any new functionality added 
	 * to this method in the future may have to also be added to the VM.
	 *
	 * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
	    stop0(throwableFromStop);
	}
    }

 

从上面的源码看出,当第一次调用start()方法后,threadStatus 就被设置为非0了,当再次调用start()方法时,会首先判断threadStatus是否为0,如果不为0,则抛出IllegalThreadStateException异常。


我们一般情况是实现Runnable接口来实现多线程的,因为java中只有单继承 ,当一个雷已经继承了另一个类,这个时候无法在继承另一个类了,而接口可以多实现,所以在开发中一般都是使用实现Runable接口这种方式来实现多线程的。

但是,实现Runnable接口的类还不是线程类,要实现多线程,必须先产生实现Runnable接口的对象,再构造一个Thread类,构造时将此对象作为参数传递给Thread类

一个实现Runnable接口的java类:

public class ThreadDemo implements Runnable {

	public ThreadDemo() {

	}

	public void run() {
		doSomething();
	}

	public void doSomething() {
		System.out.println("doSmething");
	}

}

 测试类:

public class ThreadDemoTest {
	
	public static void main(String[] args) {
		ThreadDemo demo = new ThreadDemo();
		Thread thread = new Thread(demo);
		thread.start();
	}
}

 
而使用继承Thread类这种方式实现多线程要相对简单一点。

一个实现继承Thread类的java类:

public class ThreadDemo extends Thread{

	public ThreadDemo() {

	}

	public void run() {
		doSomething();
	}

	public void doSomething() {
		System.out.println("doSmething");
	}

}

 测试类:

public class ThreadDemoTest {

	public static void main(String[] args) {
		ThreadDemo demo = new ThreadDemo();
		demo.start();
	}
}

 

3.线程状态。

1>>新建:新创建了一个线程对象。

2>>就绪:线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

3>>运行:就绪状态的线程获取了CPU控制权,执行程序代码。

4>>死亡:线程执行完了或者因异常退出了run()方法,该线程结束生命周期

线程在运行时,还有几种状态:

sleep:Thread类的方法,线程在到达给定的时间以后自动醒来,进入就绪状态。

wait:Object类的方法,线程在别的线程调用notify,notifyAll之后才醒来,进入就绪状态。

yield:Thread类的方法,显示出让CPU控制权。进入就绪状态。

阻塞:等待IO输入输出

4。线程的优先级

为什么要有优先级呢?因为优先级可以保证重要的线程优先执行,而不重要的线程后执行(相对来说)。

注意,并不是优先级高的线程一定先执行,知只是说有优先级高的线程获取CPU控制权的几率更高。

线程的优先级分10个等级,分别用整数表示。最低为1级,最高为10级,分配给线程的默认优先级,取值为5。

Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。

每个线程都有一个默认的优先级,主线程的优先级为Thread.NORM_PRIORITY(5)。

5.线程同步

 线程同步的真实意思和字面意思恰好相反。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。

当多个线程同时访问同一个资源时,可能会造成数据的不一致,这时为了保持数据的一致性,需要将该资源进行同步处理,也就是说,在同一个时间内,只允许一个线程访问这个资源。

注意,如果多个线程只是读取同一资源,不对该资源的数据进行修改,这时同步是没有必要的,只有当可能对该资源的数据进行修改时才可以同步。

实现线程同步,要使用java关键字synchronized。

实现线程同步有2种方式,一种是同步方法,一种是同步块,下面具体分析。

1>>同步方法

public synchronized void save() {
		//方法体		
}

 问题:

当一个线程进入到一个对象的同步方法后,能否进入该对象的其他同步方法,非同步方法呢?

我们知道,java中的线程同步,是给对象同步,是给对象上锁。像上面的问题,多个线程同时进入同一个对象的同步方法,当第一个线程到达这个对象的方法时,会获取该对象锁,同时进入方法执行方法体,当第二个线程运行到该对象的这个方法时,会查看该对象是否被锁住,如果已经被锁住,则进入就绪状态,等待获取CPU控制权,同理,后面的线程也一样。

一个线程类:

package com.lovo.lis.thread;

public class Thread1 extends Thread {

	private Account account;

	public Thread1(Account account) {
		this.account = account;
		this.start();
	}

	@Override
	public void run() {
		account.save();
	}
}

 

第2个线程类:

package com.lovo.lis.thread;

public class Thread2 extends Thread {

	private Account account;

	public Thread2(Account account) {
		this.account = account;
		this.start();
	}

	@Override
	public void run() {
		account.save();
	}
}

 共享资源类:

package com.lovo.lis.thread;

public class Account {

	public synchronized void save() {
		System.out.println(Thread.currentThread().getName() + "线程开始进入save方法");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "线程开始退出save方法");
	}

}

  

 测试类:

package com.lovo.lis.thread;

public class Test {
	public static void main(String[] args) {
		Account account = new Account();
		Thread1 thread1 = new Thread1(account);
		Thread2 thread2 = new Thread2(account);
	}
}

 

运行上面的程序:

结果如下:

 

Thread-0线程开始进入save方法
Thread-0线程开始退出save方法
Thread-1线程开始进入save方法
Thread-1线程开始退出save方法

 从结果看出,线程被同步了,原因是对Account对象只有一个,也就是说Account对象是同步锁对象。2个线程都是访问同一个对象,当第一个线程获取这个锁之后,Account对象就被同步了。

那如果现在将代码改为下面这种情况,结果又会是什么样的呢?

package com.lovo.lis.thread;

public class Test {
	public static void main(String[] args) {
		Account account = new Account();
		Thread1 thread1 = new Thread1(new Account());
		Thread2 thread2 = new Thread2(new Account());
	}
}

 

Accout类产生了2个对象,分别对应给2个线程,这时,运行结果如下:

Thread-0线程开始进入save方法
Thread-1线程开始进入save方法
Thread-0线程开始退出save方法
Thread-1线程开始退出save方法

 

可以看出,此时未被同步,原因是产生了2个共享资源对象,不是同一个共享资源,当然起不到同步的作用了。

考虑这种情况:如果其中一个线程进入共享资源的同步方法后,其他线程能否进入该资源的其他同步方法?

还是以上面的代码为例,修改共享资源类:

package com.lovo.lis.thread;

public class Account {

	public synchronized void save() {
		System.out.println(Thread.currentThread().getName() + "线程开始进入save方法");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "线程开始退出save方法");
	}
	
	public   void getMoney(){
		System.out.println(Thread.currentThread().getName() + "线程开始进入getMoney方法");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "线程开始退出getMoney方法");
	}
}

 

 

 修改Thread2类:

package com.lovo.lis.thread;

public class Thread2 extends Thread {

	private Account account;

	public Thread2(Account account) {
		this.account = account;
		this.start();
	}

	@Override
	public void run() {
		account.getMoney();
	}
}

 

Thread1类保持不变

package com.lovo.lis.thread;

public class Test {
	public static void main(String[] args) {
		Account account = new Account();
		Thread1 thread1 = new Thread1(account);
		Thread2 thread2 = new Thread2(account);
	}
}

 

结果:

Thread-0线程开始进入save方法
Thread-1线程开始进入getMoney方法
Thread-0线程开始退出save方法
Thread-1线程开始退出getMoney方法

 

 

可以看出,如果其中一个线程进入共享资源的同步方法后,其他线程可以进入该资源的其他非同步方法

那如果是同步方法呢,请注意,这里是同一个共享资源。

修改共享资源类:

package com.lovo.lis.thread;

public class Account {

	public synchronized void save() {
		System.out.println(Thread.currentThread().getName() + "线程开始进入save方法");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "线程开始退出save方法");
	}
	
	public synchronized  void getMoney(){
		System.out.println(Thread.currentThread().getName() + "线程开始进入getMoney方法");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "线程开始退出getMoney方法");
	}
}

 

结果:

Thread-0线程开始进入save方法
Thread-0线程开始退出save方法
Thread-1线程开始进入getMoney方法
Thread-1线程开始退出getMoney方法

 

于是可以得出结论:

如果其中一个线程进入共享资源的同步方法后,其他线程不能进入该资源的其他同步方法,而非同步方法则可以。

 

2>>同步块

public void getMoney(){
		synchronized(Account.class){
			//方法体
		}
}

 由于synchronized后面的括号内可以跟任何的数据类型,所以,同步块比同步方法更加灵活,在开发中用的更多。

还是以上面为例,还是那个问题:

如果其中一个线程进入共享资源的同步块后,其他线程能否进入该资源的其他同步块呢?

共享资源类:

 

 

 

package com.lovo.lis.thread;

public class Account {

	public void save() {
		synchronized (Account.class) {
			System.out.println(Thread.currentThread().getName() + "线程开始进入save方法");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "线程开始退出save方法");
		}
	}

	public void getMoney() {
		synchronized (Account.class) {

			System.out.println(Thread.currentThread().getName()
					+ "线程开始进入getMoney方法");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()
					+ "线程开始退出getMoney方法");
		}
	}
}

 线程类1:

package com.lovo.lis.thread;

public class Thread1 extends Thread {

	private Account account;

	public Thread1(Account account) {
		this.account = account;
		this.start();
	}

	@Override
	public void run() {
		account.save();
	}
}

 

  线程类2:

package com.lovo.lis.thread;

public class Thread2 extends Thread {

	private Account account;

	public Thread2(Account account) {
		this.account = account;
		this.start();
	}

	@Override
	public void run() {
		account.getMoney();
	}
}

 

测试类:

package com.lovo.lis.thread;

public class Test {
	public static void main(String[] args) {
		Account account = new Account();
		Thread1 thread1 = new Thread1(new Account());
		Thread2 thread2 = new Thread2(new Account());
	}
}

运行结果:

Thread-0线程开始进入save方法
Thread-0线程开始退出save方法
Thread-1线程开始进入getMoney方法
Thread-1线程开始退出getMoney方法

  

此时,同步块里面传入的是Account类的Class对象,所以不管new多少个Account类的对象,当一个线程进入到这个account类的同步块之后,不能访问这个类的其他同步方法。

而如果将synchronized (Account.class) {}的Account.class改为new account(),则永远不会被同步。

修改共享资源类:

 

 

package com.lovo.lis.thread;

public class Account {

	public void save() {
		synchronized (new Account()) {
			System.out.println(Thread.currentThread().getName() + "线程开始进入save方法");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "线程开始退出save方法");
		}
	}

	public void getMoney() {
		synchronized (new Account()) {

			System.out.println(Thread.currentThread().getName()
					+ "线程开始进入getMoney方法");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()
					+ "线程开始退出getMoney方法");
		}
	}
}

 

运行结果如下:

Thread-0线程开始进入save方法
Thread-1线程开始进入getMoney方法
Thread-0线程开始退出save方法
Thread-1线程开始退出getMoney方法

 和上面预料的完全一样。

结束语:

有关线程的知识就先写到此了,如有错误,请指正。

 

0
0
分享到:
评论

相关推荐

    多线程知识总结

    ### 多线程知识总结 #### 一、线程基础概念 **线程状态:** 在探讨多线程之前,我们需要了解线程的基本状态转换。一个典型的线程生命周期包括以下几个阶段: 1. **Start(启动):** 当线程被创建后调用`start()`...

    Java多线程知识点总结

    了解线程池的概念也是Java多线程编程中的一个重要知识点。线程池是一种多线程处理形式,它将线程和任务的概念分离开来,能够有效管理线程资源,减少线程创建和销毁的开销,提高程序性能。Java中可以通过Executors类...

    Java多线程知识点整理.pdf

    Java多线程知识点整理.pdf

    JAVA中的线程知识点整理

    以下是对Java线程相关知识点的详细说明: 1. **线程的创建与执行** - 创建线程有两种方式:继承`Thread`类或者实现`Runnable`接口。继承`Thread`直接重写`run()`方法,而实现`Runnable`接口则需要提供一个包含业务...

    Java线程知识总结

    Java线程知识是Java开发中不可或缺的部分,尤其在构建高性能、高并发的应用程序时显得尤为重要。线程允许程序在同一时间处理多个任务,提高了CPU的利用率和程序的响应速度。 在Java中,线程是由Java虚拟机(JVM)...

    Java多线程知识,龙果学院

    "Java多线程知识,龙果学院"这一课程显然是针对这部分内容进行深入讲解的资源,旨在帮助开发者提升在多任务环境下的编程能力。 一、Java多线程基础 1. **线程的概念**:线程是程序执行的最小单元,一个进程可以有...

    java多线程知识讲解及练习题

    Java 多线程知识讲解及练习题 Java 多线程基础知识的了解是 Java 程序设计的重要组成部分,本资源摘要信息对 Java 多线程基础知识进行了详细的讲解和练习题。 1. sleep() 和 wait() 的区别 sleep() 是 Thread 类...

    Thread线程知识体系 源码

    理解并掌握线程知识对于编写高效、可扩展的多线程程序至关重要。在这个"Thread线程知识体系 源码"中,我们可以深入探究Java线程的实现原理和最佳实践。 首先,`pom.xml`是一个Maven项目的配置文件,它定义了项目...

    Java多线程知识点思维导图

    对Java线程总体知识的梳理,主要描述了关键知识点,可以梳理一下思路!

    java线程知识的相关代码

    以下是对给定内容中涉及的Java线程知识的详细说明: **线程的创建** 1. **继承Thread类**:这是创建线程的直接方式。如示例中的`Demo`类,它继承了`Thread`类,并重写了`run()`方法。`run()`方法包含了线程要执行的...

    多线程知识点

    多线程在我们的开发应用中也是回很常用的,希望里面的内容能够可以帮助到你们解决掉你们想要的问题,这是我所期望看到的

    63-Java多线程知识点总结1

    Java多线程知识点总结 Java多线程知识点总结主要讲解了Java中多线程编程的基础知识,包括线程的启动、volatile变量、多线程共享数据、wait、notify、notifyAll等。 线程的启动 在Java中,线程的启动可以通过start...

    Java线程知识深入解析[定义].pdf

    Java 线程知识深入解析 Java 线程知识深入解析是一种重要的组成部分之一,在 Java 中,任何一个 Applet 的 paint() 和 update() 方法都是由 AWT(Abstract Window Toolkit) 绘图与事件处理线程调用的,而 Applet ...

    VC串口多线程知识汇总

    本篇文章将围绕"VC串口多线程知识汇总"的主题,结合提供的文件内容进行详细讲解。 首先,我们来了解一下串口通信。串口通信是一种通过串行数据传输的方式,通常用于设备间的短距离通信。在VC++中,实现串口通信主要...

    java线程知识点总结[归类].pdf

    Java 线程知识点总结 Java 线程是一种轻量级的进程,它是进程中的一个独立的控制单元,线程在控制着进程的执行。每个进程至少有一个线程。Java 虚拟机(JVM)启动时会有一个进程 java.exe,该进程至少有一个线程...

    Java线程知识深入解析[收集].pdf

    《Java线程知识深入解析》 Java线程是软件开发中的核心概念,特别是在多任务处理和并发编程中扮演着至关重要的角色。线程是进程中的单一顺序控制流,是操作系统调度的基本单元。在Java中,线程是程序执行的核心组成...

    java 多线程知识点思维导读

    java 多线程知识点思维导读

    多线程知识点.xmind

    多线程知识点.xmind

    多线程知识学习整理一阶段

    多线程知识学习整理一阶段

Global site tag (gtag.js) - Google Analytics