114培训网欢迎您来到长沙牛耳教育!

13077355435

全国统一学习专线 9:00-21:00

多线程的java 程序如何编写?

Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

新建状态:

使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

就绪状态:

当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

运行状态:

如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

阻塞状态:

如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

同步阻塞:线程在获取 同步锁失败(因为同步锁被其他线程占用)。

其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

死亡状态:

一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

java多线程编程中涉及的基础知识点?

线程设计在软件开发领域中是非常常见的一个设计构成,今天霍营北大青鸟就一起来了解一下,java多线程编程中都涉及到了哪些基础知识点。



顺序


用于表示多个操作“依次处理”。比如把十个操作交给一个人来处理时,这个人要一个一个地按顺序来处理


并行


用于标识多个操作“同时处理”。比如十个操作分给两个人处理时,这两个人就会并行来处理。


并发


相对于顺序和并行来说比较抽象,用于表示“将一个操作分割成多个部分并且允许无序处理”。比如将十个操作分成相对独立的两类,这样便能够开始并发处理了。如果一个人来处理,这个人就是顺序处理分开的并发操作,而如果是两个人,这两个人就可以并行处理同一个操作。


总结


多线程程序都是并发处理的。如果CPU只有一个,那么并发处理就是顺序执行的,而如果有多个CPU,那么并发处理就可能会并行运行。


等待队列


所有实例都拥有一个等待队列,它是在实例的wait方法执行后停止操作的线程队列。就好比为每个实例准备的线程休息室


在执行wait方法后,线程便会暂停操作,进入等待队列这个休息室。除非发生下列某一情况,否则线程会一直在等待队列中休眠。


有其他线程的notify方法来唤醒线程


有其他线程的notifyAll方法来唤醒线程


有其他线程的interrupt方法来唤醒线程


wait方法超时


notify方法


该方法会将等待队列中的一个线程去除。同wait方法一样,若要执行notify方法,线程也必须持有要调用的实例的锁。


notifyAll方法


notify方法仅唤醒一个线程,而notifyAll则唤醒所有线程,这是两者之间的区别


同wait方法和notify方法一样,notifyAll方法也只能由持有要调用的实例锁的线程调用


notify和notifyAll选择


notify方法和notifyAll方法非常相似,到底该使用哪个?


实际上,这很难选择,由于notify唤醒的线程较少,所以处理速度要比使用notifyAll时快。但使用notify时,如果处理不好,程序便可能会停止。一般来说,使用notifyAll时的代码要比使用notify时的更为健壮。


什么是Java多线程编程?

一、 什么是多线程:

我们现在所使用操作系统都是多任务操作系统(早期使用的DOS操作系统为单任务操作系统),多任务操作指在同一时刻可以同时做多件事(可以同时执行多个程序)。

多进程:每个程序都是一个进程,在操作系统中可以同时执行多个程序,多进程的目的是为了有效的使用CPU资源,每开一个进程系统要为该进程分配相关的系统资源(内存资源)

多线程:线程是进程内部比进程更小的执行单元(执行流|程序片段),每个线程完成一个任务,每个进程内部包含了多个线程每个线程做自己的事情,在进程中的所有线程共享该进程的资源;

主线程:在进程中至少存在一个主线程,其他子线程都由主线程开启,主线程不一定在其他线程结束后结束,有可能在其他线程结束前结束。Java中的主线程是main线程,是Java的main函数;

二、 Java中实现多线程的方式:

继承Thread类来实现多线程:

当我们自定义的类继承Thread类后,该类就为一个线程类,该类为一个独立的执行单元,线程代码必须编写在run()方法中,run方法是由Thread类定义,我们自己写的线程类必须重写run方法。

run方法中定义的代码为线程代码,但run方法不能直接调用,如果直接调用并没有开启新的线程而是将run方法交给调用的线程执行

要开启新的线程需要调用Thread类的start()方法,该方法自动开启一个新的线程并自动执行run方法中的内容

请点击输入图片描述

结果:

请点击输入图片描述

java多线程的启动顺序不一定是线程执行的顺序,各个线程之间是抢占CPU资源执行的,所有有可能出现与启动顺序不一致的情况。

CPU的调用策略:

如何使用CPU资源是由操作系统来决定的,但操作系统只能决定CPU的使用策略不能控制实际获得CPU执行权的程序。

线程执行有两种方式:

1.抢占式:

目前PC机中使用最多的一种方式,线程抢占CPU的执行权,当一个线程抢到CPU的资源后并不是一直执行到此线程执行结束,而是执行一个时间片后让出CPU资源,此时同其他线程再次抢占CPU资源获得执行权。

2.轮循式;

每个线程执行固定的时间片后让出CPU资源,以此循环执行每个线程执行相同的时间片后让出CPU资源交给下一个线程执行。

希望对您有所帮助!~

java如何实现多线程编程

1、public class MyThread extends Thread{//重写run()方法public void run(){ //多线程要做的事}public static void main(String args[]){ MyThread m1 = new MyThread(); MyThread m2 = new MyThread(); m1.start(); m2.start();}} 2、public class NThread Runable{ //实现run()方法 public void run(){ //多线程要做的事 } public static void main(String args[]){ NThread nt = new NThread(); new Thread(nt,"nt1_name").start(); new Thread(nt,"nt2_name").start(); }}

java多线程开发的同步机制有哪些

Java同步
标签: 分类:
一、关键字:
thread(线程)、thread-safe(线程安全)、(并发的)
(同步的)、(异步的)、
volatile(易变的)、atomic(原子的)、share(共享)
二、总结背景:
一次读写共享文件编写,嚯,好家伙,竟然揪出这些零碎而又是一路的知识点。于是乎,Google和翻阅了《Java参考大全》、《Effective Java Second Edition》,特此总结一下供日后工作学习参考。
三、概念:
1、 什么时候必须同步?什么叫同步?如何同步?
要跨线程维护正确的可见性,只要在几个线程之间共享非 final 变量,就必须使用 (或 volatile)以确保一个线程可以看见另一个线程做的更改。
为了在线程之间进行可靠的通信,也为了互斥访问,同步是必须的。这归因于java语言规范的内存模型,它规定了:一个线程所做的变化何时以及如何变成对其它线程可见。
因为多线程将异步行为引进程序,所以在需要同步时,必须有一种方法强制进行。例如:如果2个线程想要通信并且要共享一个复杂的数据结构,如链表,此时需要
确保它们互不冲突,也就是必须阻止B线程在A线程读数据的过程中向链表里面写数据(A获得了锁,B必须等A释放了该锁)。
为了达到这个目的,java在一个旧的的进程同步模型——监控器(Monitor)的基础上实现了一个巧妙的方案:监控器是一个控制机制,可以认为是一个
很小的、只能容纳一个线程的盒子,一旦一个线程进入监控器,其它的线程必须等待,直到那个线程退出监控为止。通过这种方式,一个监控器可以保证共享资源在
同一时刻只可被一个线程使用。这种方式称之为同步。(一旦一个线程进入一个实例的任何同步方法,别的线程将不能进入该同一实例的其它同步方法,但是该实例
的非同步方法仍然能够被调用)。
错误的理解:同步嘛,就是几个线程可以同时进行访问。
同步和多线程关系:没多线程环境就不需要同步;有多线程环境也不一定需要同步。
锁提供了两种主要特性:互斥(mutual exclusion) 和可见性()。
互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。
可见性要更加复杂一些,documents它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题
小结:为了防止多个线程并发对同一数据的修改,所以需要同步,否则会造成数据不一致(就是所谓的:线程安全。如java集合框架中Hashtable和
Vector是线程安全的。我们的大部分程序都不是线程安全的,因为没有进行同步,而且我们没有必要,因为大部分情况根本没有多线程环境)。
2、 什么叫原子的(原子操作)?
Java原子操作是指:不会被打断地的操作。(就是做到互斥 和可见性?!)
那难道原子操作就可以真的达到线程安全同步效果了吗?实际上有一些原子操作不一定是线程安全的。
那么,原子操作在什么情况下不是线程安全的呢?也许是这个原因导致的:java线程允许线程在自己的内存区保存变量的副本。允许线程使用本地的私有拷贝进
行工作而非每次都使用主存的值是为了提高性能(本人愚见:虽然原子操作是线程安全的,可各线程在得到变量(读操作)后,就是各自玩
弄自己的副本了,更新操作(写操作)因未写入主存中,导致其它线程不可见)。
那该如何解决呢?因此需要通过java同步机制。
在java中,32位或者更少位数的赋值是原子的。在一个32位的硬件平台上,除了double和long型的其它原始类型通常都
是使用32位进行表示,而double和long通常使用64位表示。另外,对象引用使用本机指针实现,通常也是32位的。对这些32位的类型的操作是原
子的。
这些原始类型通常使用32位或者64位表示,这又引入了另一个小小的神话:原始类型的大小是由语言保证的。这是不对的。java语言保证的是原始类型的表
数范围而非JVM中的存储大小。因此,int型总是有相同的表数范围。在一个JVM上可能使用32位实现,而在另一个JVM上可能是64位的。在此再次强
调:在所有平台上被保证的是表数范围,32位以及更小的值的操作是原子的。
3、 不要搞混了:同步、异步
举个例子:普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完返回 这个期间客户端浏览器不能干任何事
异步:请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
可见,彼“同步”非此“同步”——我们说的java中的那个共享数据同步()
一个同步的对象是指行为(动作),一个是同步的对象是指物质(共享数据)。
4、 Java同步机制有4种实现方式:(部分引用网上资源)
① ② ( ) ③ wait() 与 notify() ④ volatile
目的:都是为了解决多线程中的对同一变量的访问冲突

保证不同线程拥有不同实例,相同线程一定拥有相同的实例,即为每一个使用该变量的线程提供一个该变量值的副本,每一个线程都可以独立改变自己的副本,而不是与其它线程的副本冲突。
优势:提供了线程安全的共享对象
与其它同步机制的区别:同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信;而 是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源,这样当然不需要多个线程进行同步了。
volatile
volatile 修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。
优势:这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
缘由:Java
语言规范中指出,为了获得*速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原
始值对比。这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。而 volatile
关键字就是提示 VM :对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用技巧:在两个或者更多的线程访问的成员变量上使用 volatile 。当要访问的变量已在 代码块中,或者为常量时,不必使用。

线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步,因此存在A和B不一致
的情况。volatile就是用来避免这种情况的。
volatile告诉jvm,它所修饰的变量不保留拷贝,直接访问主内存中的(读操作多时使用较好;线程间需要通信,本条做不到)
Volatile 变量具有 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile
变量的*值。Volatile
变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值
之间没有约束。
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
对变量的写操作不依赖于当前值;该变量没有包含在具有其他变量的不变式中。
sleep() vs wait()
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
(如果变量被声明为volatile,在每次访问时都会和主存一致;如果变量在同步方法或者同步块中被访问,当在方法或者块的入口处获得锁以及方法或者块退出时释放锁时变量被同步。)

java多线程编程

楼主出现问题有2点:
1. wake() 这个方法也要同步啊,加关键字 ;
2. *次调用st()方法后,available应该保持不变,这样才能保证线程b也打印..start,所以加个if判断一下就ok啦。

public class ABC {

boolean available=false;
String name;
int count=0;
public ABC(String name){
this.name=name;
}
public void st(){
System.out.println("... start.");
count++;
if(count>1){
available=true;
}
try{
wait();
}catch(Exception e){}
System.out.println("... end.");
}
public void end(){
System.out.println("... end.");
}
public void wake() {
notifyAll();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ABC x=new ABC("haha");
a=new (x);
b=new (x);
C c=new C(x);
(new Thread(a)).start();
(new Thread(b)).start();
(new Thread(c)).start();
}
}
class Runnable{
ABC abc;
public (ABC abc){
this.abc=abc;
}
public void run(){
if(!abc.available){
abc.st();
}
else abc.end();

}
}
class C Runnable{
ABC abc;
public C(ABC abc){
this.abc=abc;
}
public void run(){
try{
Thread.sleep(1000);
// System.out.println("sjlfsj jfsdl j"); //验证是否执行到这里
}catch( e){};
abc.wake();
}
}

JAVA多线程编程的几种表示方法

创建线程有两种方法:继承Thread类和实现Runnable接口。
方法一:继承 Thread 类,覆盖方法 run(),我们在创建的 Thread 类的子类中重写 run() ,加入线程所要执行的代码即可。下面是一个例子:
public class MyThread extends Thread {
int count= 1, number;
public MyThread(int num) {
number = num;
System.out.println("创建线程 " + number);
}
public void run() {
while(true) {
System.out.println("线程 " + number + ":计数 " + count);
if(++count== 6) return;
}
}
public static void main(String args[]) {
for(int i = 0; i < 5; i++) new MyThread(i+1).start();
}
}
方法二:实现 Runnable 接口
Runnable 接口只有一个方法 run(),我们声明自己的类实现 Runnable 接口并提供这一方法,将我们的线程代码写入其中,就完成了这一部分的任务。但是 Runnable 接口并没有任何对线程的支持,我们还必须创建 Thread 类的实例,这一点通过 Thread 类的构造函数public Thread(Runnable target);来实现。下面是一个例子:
public class MyThread Runnable {
int count= 1, number;
public MyThread(int num) {
number = num;
System.out.println("创建线程 " + number);
}
public void run() {
while(true) {
System.out.println("线程 " + number + ":计数 " + count);
if(++count== 6) return;
}
}
public static void main(String args[]) {
for(int i = 0; i < 5; i++) new Thread(new MyThread(i+1)).start();
}
}
两种方法各有千秋,可以灵活运用。

什么是多线程编程

多线程编程技术是Java语言的重要特点。多线程编程的含义是将程序任务分成几个并行的子任务。特别是在网络编程中,你会发现很多功能是可以并发执行的。 比如网络传输速度较慢、用户输入速度较慢,你可以用两个独立的线程去完成这两个功能,而不影响正常的显示或其它功能。 多线程是与单线程比较而言的,普通的Windows采用单线程程序结构,其工作原理是:主程序有一个消息循环,不断从消息队列中读入消息来决定下一步所要干的事情,一般是针对一个函数,只有等这个函数执行完之后,主程序才能接收另外的消息来执行。比如子函数功能是在读一个网络数据,或读一个文件,只有等读完这个数据或文件才能接收下一个消息。在执行这个子函数过程中你什么也不能干。但往往读网络数据和等待用户输入有很多时间处于等待状态,多线程利用这个特点将任务分成多个并发任务后,就可以解决这个问题。Java中的线程类 1.扩展java.lang.Thread类,用它覆盖Thread类的run方法。 2.生成实现java.lang.Runnable接口的类并将其它的实例与java.lang.Thread实例相关联。 Thread类是负责向其它类提供线程支持的最主要的类,要使用一个类具有线程功能,在Java中只要简单地从Thread类派生一个子类就可以了扩展Thread类,如.java。 Thread类最重要的方法是run方法。run方法是新线程执行的方法,因此生成java.lang.Thread的子类时,必须有相应的run方法。 //.java public class extends Thread//继承Tread类 private int count=0 //定义一个count变量用于统计打印的次数并共享变量 public static void args//main方法开始 p=new //创建一个线程实例 p.start//执行线程 for{;;}//主线程main方法执行一个循环,for执行一个死循环count++ System.out.+″:Mainn″//主线程中打印count +“main”变量的值,并换行 public void run//线程类必须有的run()方法for{;;}count++ System.out.+″:Threadn″ 上面这段程序便是继承java.lang.Tread并覆盖run的方法。用Java 虚拟机启动程序时,这个程序会先生成一个线程并调用程序主类的main方法。这个程序中的main方法生成新线程,连接打印“Thread”。在启动线程之后,主线程继续打印“Main”。 编译并执行这个程序,然后立即按“Ctrl+C”键中断程序,你会看到上面所述的两个线程不断打印出:XXX:main…..XXX:Thread…. XXX代表的是数字,也就是上面count的值。在笔者的机器上,不同时刻这两个线程打印的次数不一样,先打印20个main(也就是先执行20次主线程)再打印出50次Thread,然后再打印main…… 提示:为了便于查看该程序的执行结果,你可以将执行结果导入一个文本文件,然后打开这个文件查看各线程执行的情况。如运行: javac .java Java .txt *个命令javac .java是编译java程序,第二个是执行该程序并将结果导入1.txt文件。当然你可以直接执行命令:java

java Socket编程实现的最简单的多线程Web服务器

import java.io.;
import java.net.;
import java.net.Socket;
public class Test {
public static void main(String[] args) throws Exception {
server = new (888);
while(true) {
Socket s = server.accept();
Processer p = new Processer(s);
Thread t = new Thread(p);
t.start();
}
}
}
class Processer Runnable {
private Socket socket;

public Processer(Socket s) {
// TODO Auto-generated stub
this.socket = s;
}
@Override
public void run() {
try {
out=new (socket.(),true);
out.println("HTTP/1.0 200 OK");
out.println("Content-Type:text/html;charset=utf-8");
out.println();
out.println("<h1> Web服务器测试成功!</h1>");
out.close();
} catch(Exception ex) {
ex.();
} finally {
try {
socket.close();
} catch (Exception e) {
e.();
}
}

}
}

能不能简单描述一下你在java web开发中需要用到多线程编程的场景?

最典型的应用比如tomcat,tomcat内部采用的就是多线程,上百个客户端访问同一个web应用,tomcat接入后都是把后续的处理扔给一个新的线程来处理,这个新的线程*调用到我们的servlet程序,比如doGet或者doPost方法。 如果不采用多线程机制,上百个人同时访问一个web应用的时候,tomcat就得排队串行处理了,那样客户端根本是无法忍受那种访问速度的。 还有就是需要异步处理的时候,需要使用多线程。比如task a和task b要并行处理,单个线程只能串行处理,先做完task a然后再做task b。如果想要多个task同时执行的话,就必须为每个task分配一个线程,然后通过java虚拟机的线程调度,来同时执行多个任务。比如你的CPU是多核心的话,就可以让一个CPU执行一个线程。如果只有一个CPU的话,底层是按照分时复用的原则,各个线程按照时间片来获得CPU资源。

温馨提示:为不影响您的学业,来校区前请先电话咨询,方便我校安排相关的专业老师为您解答
  • 详情请进入长沙牛耳教育
  • 已关注:98263
  • 咨询电话:
相关资料
姓名不能为空
手机号格式错误