- 浏览: 53873 次
- 性别:
- 来自: 成都
最新评论
-
somefuture:
Object object = new Object() { ...
使用new和反射产生java内部类的实例化对象 -
段箭*残箫:
<div class="quote_title ...
有关java中的Date,String,Timestamp之间的转化问题 -
段箭*残箫:
<div class="quote_title ...
有关java中的Date,String,Timestamp之间的转化问题 -
ArcTan:
<div class="quote_title ...
有关java中的Date,String,Timestamp之间的转化问题 -
mercyblitz:
引用还发现一件怪异的事情:
// String转化成date ...
有关java中的Date,String,Timestamp之间的转化问题
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方法
和上面预料的完全一样。
结束语:
有关线程的知识就先写到此了,如有错误,请指正。
发表评论
-
有关java中的Date,String,Timestamp之间的转化问题
2010-06-17 16:33 9144一.获取系统当前时间: 1.System.out.print ... -
JAVA编程常见错误集锦
2010-05-14 00:25 6773本文转自:http://hi.baidu.com/zzcc_8 ... -
web编程--java web开发模式
2010-05-10 21:25 1871一.java web开发模式的变 ... -
web编程--http协议和servlet之我见
2010-05-09 20:37 2557http协议: 超文本传输协议,是一种无状态协 ... -
线程的优缺点
2010-04-21 23:56 2000何时使用多线程技术,何 ... -
Java面试题
2010-03-16 10:35 1292一、Java基础知识1.Java有那些基本数据类型,Strin ... -
Java性能的优化
2009-12-13 16:06 1017Java在九十年代中期出现以后,在赢得赞叹的同时,也引来了一些 ... -
使用new和反射产生java内部类的实例化对象
2009-12-12 14:29 14164前两天看到一道面试题 ... -
java对象的序列化和反序列化
2009-12-11 00:30 1100关键字: java对象的序列 ... -
面试Java
2009-11-04 09:40 955java 面试题 Java面试题和答案 JAVA相关基础知识 ... -
正则表达式口诀及教程
2009-11-03 20:38 1179正则表达式口诀及教程(推荐)由 Knightby 撰写 ht ... -
Hibernate的get和load方法的区别
2009-10-30 03:09 1665Hibernate的get和load方法都是用于查询一条记录, ...
相关推荐
### 多线程知识总结 #### 一、线程基础概念 **线程状态:** 在探讨多线程之前,我们需要了解线程的基本状态转换。一个典型的线程生命周期包括以下几个阶段: 1. **Start(启动):** 当线程被创建后调用`start()`...
了解线程池的概念也是Java多线程编程中的一个重要知识点。线程池是一种多线程处理形式,它将线程和任务的概念分离开来,能够有效管理线程资源,减少线程创建和销毁的开销,提高程序性能。Java中可以通过Executors类...
Java多线程知识点整理.pdf
以下是对Java线程相关知识点的详细说明: 1. **线程的创建与执行** - 创建线程有两种方式:继承`Thread`类或者实现`Runnable`接口。继承`Thread`直接重写`run()`方法,而实现`Runnable`接口则需要提供一个包含业务...
Java线程知识是Java开发中不可或缺的部分,尤其在构建高性能、高并发的应用程序时显得尤为重要。线程允许程序在同一时间处理多个任务,提高了CPU的利用率和程序的响应速度。 在Java中,线程是由Java虚拟机(JVM)...
"Java多线程知识,龙果学院"这一课程显然是针对这部分内容进行深入讲解的资源,旨在帮助开发者提升在多任务环境下的编程能力。 一、Java多线程基础 1. **线程的概念**:线程是程序执行的最小单元,一个进程可以有...
Java 多线程知识讲解及练习题 Java 多线程基础知识的了解是 Java 程序设计的重要组成部分,本资源摘要信息对 Java 多线程基础知识进行了详细的讲解和练习题。 1. sleep() 和 wait() 的区别 sleep() 是 Thread 类...
理解并掌握线程知识对于编写高效、可扩展的多线程程序至关重要。在这个"Thread线程知识体系 源码"中,我们可以深入探究Java线程的实现原理和最佳实践。 首先,`pom.xml`是一个Maven项目的配置文件,它定义了项目...
对Java线程总体知识的梳理,主要描述了关键知识点,可以梳理一下思路!
以下是对给定内容中涉及的Java线程知识的详细说明: **线程的创建** 1. **继承Thread类**:这是创建线程的直接方式。如示例中的`Demo`类,它继承了`Thread`类,并重写了`run()`方法。`run()`方法包含了线程要执行的...
多线程在我们的开发应用中也是回很常用的,希望里面的内容能够可以帮助到你们解决掉你们想要的问题,这是我所期望看到的
Java多线程知识点总结 Java多线程知识点总结主要讲解了Java中多线程编程的基础知识,包括线程的启动、volatile变量、多线程共享数据、wait、notify、notifyAll等。 线程的启动 在Java中,线程的启动可以通过start...
Java 线程知识深入解析 Java 线程知识深入解析是一种重要的组成部分之一,在 Java 中,任何一个 Applet 的 paint() 和 update() 方法都是由 AWT(Abstract Window Toolkit) 绘图与事件处理线程调用的,而 Applet ...
本篇文章将围绕"VC串口多线程知识汇总"的主题,结合提供的文件内容进行详细讲解。 首先,我们来了解一下串口通信。串口通信是一种通过串行数据传输的方式,通常用于设备间的短距离通信。在VC++中,实现串口通信主要...
Java 线程知识点总结 Java 线程是一种轻量级的进程,它是进程中的一个独立的控制单元,线程在控制着进程的执行。每个进程至少有一个线程。Java 虚拟机(JVM)启动时会有一个进程 java.exe,该进程至少有一个线程...
《Java线程知识深入解析》 Java线程是软件开发中的核心概念,特别是在多任务处理和并发编程中扮演着至关重要的角色。线程是进程中的单一顺序控制流,是操作系统调度的基本单元。在Java中,线程是程序执行的核心组成...
java 多线程知识点思维导读
多线程知识点.xmind
多线程知识学习整理一阶段