基于JAVA语言的多线程技术
1、简介
多线程技术属于操作系统范围内的知识;
进程与线程
可以这么理解,一个应用程序就是一个进程,在一个进程中包含至少一个线程;进程就是线程的容器,真正工作、处理任务的是线程。
进程是操作系统分配资源的基本单位;线程是操作系统进行调度,时间分配的基本单位;
进程由内核对象和地址空间两部分构成,内核对象就是一小块记录进程信息的内存,只允许操作系统访问;地址空间就是存放数据和程序的空间;
2、多线程运行机制
对于单个CPU,在每个时间点只能只能执行一个线程,多线程的实现是基于对时间片的轮回机制的,即为每一个线程分配一个极短的时间片;时间片结束了就执行另一个线程,关于时间片的分配是由操作系统完成的,应用程序无法改变。应用程序可以设置线程的优先级。
关于线程的优先级,对于windows操作系统,线程的优先级是根据所在进程的优先级类和线程的相对优先级类进行确定的,方法如图:
注意,进程优先级一般不要设置为real-time会出问题的。
然后说一下优先级的作用,优先级越高,分配的时间片越长;优先级不等同于执行顺序,线程的执行顺序受操作系统的很多因素影响,优先级只可能是其中的一个因素,所以指望利用优先级控制线程的执行顺序是不现实的。
另外不同语言对优先级的规定也不同,而且优先级适合操作系统和平台相关的,利用优先级控制程序,在一个平台中运行很好,而在另一个平台中就可能会出问题。
3、线程的生命周期(基于Java语言)
new(创建线程)、run/start(执行线程)、block(阻塞线程)、wait(释放锁,并等待唤醒)、destroy(死亡)
对于run和start 尽量选择用start ,因为虽然run是线程真正的处理程序,但是调用run就相当于调用了一个方法,run不结束,是不会执行后面的语句的;而调用start会自动调用run,并且无论run是否运行完毕,都会执行后面的程序,这才是真正意义上启动一个线程;
4、基于Java 多线程的实现
基于Java实现多线程有两种方式,一个是通过继承thread类,另一个是继承runnable接口;两种方式本质上没有太多区别,因为thread类本身也是继承了Runnable接口的,只不过在进行了一些封装而已。两种方式在使用上是由区别的,如果一个类已经继承了其他类,便不能再集成thread类了,所以只能使用第二种方法。
继承于thread类的类,可以直接调用thread的方法;
大概是这样的
public class testThread1 extend Thread
{
/**
*重写run方法
*/
public void run()
{
}
} //调用方式
testThread1 threadInstance = new testThread1 ();
threadInstance.start(); //自动执行run方法
方式一
继承于runnable接口的类,必须实例化后,然后用实例化后的对象初始化一个thread对象;
大概是这样的
public class testThread2 implements Runnable
{
/**
*重写run方法
*/
public void run()
{
}
} //调用方式
testThread2 threadInstance = new testThread2 ();
Thread real_threaInstance = new Thread(threadInstance );
real_threaInstance .start(); //自动执行run方法
方式二
本质上都是对runnable的run方法进行重写,run中的函数就是线程要执行的函数。
5、基于Java的多线程通信
多线程之间的通信自己分类,分为三种:(1)共享变量 (2)消息机制 (3)管道机制(暂时不了解还)
(1)共享变量
各个线程共享进程的地址空间,所以就都可以访问进程中的公共地址空间,这样在公共地址空间中的变量就可以被各个线程访问;如果进程中的地址空间被分配给某个线程,那么其他线程就不可以访问了。
(2)消息机制
主要介绍sleep join wait notify synchronized的应用
synchronized:为obj对象加锁,调用方法 synchronized(obj){} //obj是一个对象 只要继承于object类即可 如: string类型 在Java中,每一个继承于object类的对象都有一个琐,当对这个对象枷锁之后,其他线程便不能够再访问这个对象了;
sleep:使线程休眠一定的时间,在休眠过程中不是释放锁
wait: 有两种调用方式 wait(1000) //指定休眠时间 wait() //不指定休眠时间,在休眠过程中 会释放锁;wait() 必须放在synchronized代码块中,因为只有加锁之后,才可以释放锁,释放的就是synchronized(obj) obj的锁;否则就会报异常;
notify:唤醒一个wait线程
从语法上来讲,wait() 与 notify()都必须位于synchronized块内;
对于一个对象的锁,wait和notify是这样配合的:首先加锁,调用锁的wait方法,阻塞线程,然后等待这个锁的notify方法被调用,被调用之后,停止wait,执行线程后面的程序。
子线程.join() 是阻塞主线程,等待子线程完成后再执行主线程;如:主线程中需要用到子线程的计算结果等情况
可以利用消息机制 控制 线程的执行顺序;
6、代码示例
以下代码实现了多个客户端与服务器端建立连接并发送消息的过程,至于服务器端对客户端发送消息,这一部分没有写好,因为多个线程在等待发送消息,所以发送的时候会随机选择一个客户端。
服务器端关键代码:
/**
*
* @method: jTextArea1KeyPressed() -by fjt
* @TODO: 判断是否按下Enter键
* @param evt void
*/
private void txtAreaSendKeyPressed(java.awt.event.KeyEvent evt) {
// TODO add your handling code here:
if(evt.getKeyChar() == '\n')
{
synchronized (Sendobj) {
Sendobj.notify();
} }
} ServerSocket server = null; //服务器
int socketNo = 0; //客户端编号
/***
*
* @method: btn_stopActionPerformed() -by fjt
* @TODO: 关闭服务器
* @param evt void
*/
private void btn_stopActionPerformed(java.awt.event.ActionEvent evt) {
// 关闭服务器
try {
server.close();
MessageRecord.append("服务器关闭成功……\n");
} catch (Exception e) {
// TODO: handle exception
MessageRecord.append("服务器关闭失败……\n" + e + "\n");
}
}
/****
*
* @method: btn_startActionPerformed() -by fjt
* @TODO: 开启服务器
* @param evt void
*/
private void btn_startActionPerformed(java.awt.event.ActionEvent evt) {
// 开启服务器
MessageRecord.append("服务器启动中……\n");
try {
server = new ServerSocket(4700);
MessageRecord.append("服务器启动成功,端口:4700\n");
} catch (Exception e) {
MessageRecord.append("服务器启动失败……\n" + e + "\n");
}
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
creatSocket(server);
}
}).start();
} /***
*
* @method: creatSocket() -by fjt
* @TODO: 创建套接字函数
* @param server void
*/
Object Sendobj = new Object(); //发送线程监控器
public void creatSocket(final ServerSocket server) {
try
{
final Socket socket = server.accept(); //等待客户端连接 如果有客户端连接,则产生一个socket 对象
final String currentSocket = Integer.toString(socketNo);
socketNo++;
MessageRecord.append("客户端 " + currentSocket + " 已连接\n");
//发送消息线程
Thread sendThread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (Sendobj) {
try
{ while(true)
{
PrintWriter sendMsg = new PrintWriter(socket.getOutputStream());
sendMsg.println(txtAreaSend.getText());
sendMsg.flush();
Sendobj.wait();
}
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}); sendThread.start(); //如果调用run,就会阻碍后面的语句执行
//接受客户端消息线程
String line;
try {
final BufferedReader is = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
PrintWriter os = new PrintWriter(socket.getOutputStream()); //接受客户端信息线程
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
MessageRecord.append("client " + currentSocket
+ " : " + is.readLine() + "\n");
} catch (Exception e) {
// TODO: handle exception
MessageRecord.append(currentSocket + "读取客户端消息异常\n"
+ e + "\n");
} }
}
}).start(); } catch (Exception e) {
// TODO: handle exception
MessageRecord.append(currentSocket + "通信出现异常\n" + e + "\n");
}
//创建新的监听线程
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
creatSocket(server);
}
}).start();
//开启发送消息线程
//sendThread.run();
} catch (Exception e)
{
// TODO: handle exception
MessageRecord.append("客户端连接出现异常\n" + e + "\n");
}
} /**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ServerWatch().setVisible(true);
}
});
}
服务器端
客户端
package testSocketClient;
import java.net.*;
import java.io.*;
public class client
{
public static void main(String[] args)
{
System.out.println("Hello Client!!"); try
{
Socket socket=new Socket("127.0.0.1",4700);
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
PrintWriter os=new PrintWriter(socket.getOutputStream());
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String readline;
readline=sin.readLine(); //从系统标准输入读入一字符串
while(!readline.equals("bye"))
{
os.println(readline);
os.flush();
System.out.println("Client:"+readline);
System.out.println("Server:"+is.readLine());
readline=sin.readLine();
}
os.close(); //关闭Socket输出流
is.close(); //关闭Socket输入流
socket.close(); //关闭Socket
}
catch(Exception e)
{
System.out.println("错误信息:" + e);
}
} }
客户端
7、多线程编程中易出现的问题
(1)资源共享,但没有处理好线程同步,读取脏数据
(2)资源互斥,导致死锁问题
(3)线程同步,即线程的执行顺序
基于JAVA语言的多线程技术的更多相关文章
- 基于Java语言开发jt808、jt809技术文章精华索引
很多技术开发人员喜欢追逐最新的技术,如Node.js, go等语言,这些语言只是解决了某一个方面,如只是擅长异步高并发等等,却在企业管理后台开发方面提供的支持非常不够,造成项目团队技术选项失败,开发后 ...
- Java中的多线程技术全面详解
本文主要从整体上介绍Java中的多线程技术,对于一些重要的基础概念会进行相对详细的介绍,若有叙述不清晰或是不正确的地方,希望大家指出,谢谢大家:) 为什么使用多线程 并发与并行 我们知道,在单核机器上 ...
- JFinal -基于Java 语言的MVC极速 web 开发框架
JFinal概述 JFinal 是基于Java 语言的极速 web 开发框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restful.在拥有Java语言所有优势的同时再 ...
- java语言体系的技术简介之JSP、Servlet、JDBC、JavaBean(Application)
转自:https://zhangkunnan.iteye.com/blog/2040462 前言 Java语言 Java语言体系比较庞大,包括多个模块.从WEB项目应用角度讲有JSP.Servlet. ...
- Java 基础入门随笔(1) JavaSE版——java语言三种技术架构
1.java语言的三种技术架构: J2SE(java 2 Platform Standard Edition):标准版,是为开发普通桌面和商务应用程序提供的解决方案.该技术体系是其他两者的基础,可以完 ...
- 单循环链表(基于java语言)
public class CircleSinglyLinkList { private Node head; CircleSinglyLinkList(){ this.head = null; } C ...
- 《神经网络算法与实现-基于Java语言》的读书笔记
文章提纲 全书总评 读书笔记 C1.初识神经网络 C2.神经网络是如何学习的 C3.有监督学习(运用感知机) C4.无监督学习(自组织映射) Rreferences(参考文献) 全书总评 书本印刷质量 ...
- 基于java语言的给cube添加custom view来实现权限控制
今天是农历2014年的最后一个工作日了,在这里提前祝大家新年快乐.羊年大吉!当然本人今天也拿出来点儿真东西,做为献给大家的新年礼物,依次共勉. 下文主要讲述的是使用Java代码来完成对cube基于部门 ...
- 基于JAVA语言的selenium测试基础总结
目录一.基本语句1.循环控制(break,continue)3.字符的替换(replace,repalceFirst,replaceAll,regex)4.字符串的连接("+",a ...
随机推荐
- Ubuntu为已经安装的PHP7单独编译mysqli
编译安装PHP7后没有在ext中没有生成mysqli.so等文件,现在单独编译安装mysqli php7安装的位置:/usr/local/php7/ 我的扩展目录:/usr/local/php7/li ...
- HDU 1548 A strange lift(dij+邻接矩阵)
( ̄▽ ̄)" //dijkstra算法, //只是有效边(即能从i楼到j楼)的边权都为1(代表次数1): //关于能否到达目标楼层b,只需判断最终lowtime[b]是否等于INF即可. # ...
- hdu_5753_Permutation Bo(找规律)
题目连接:hdu_5753_Permutation Bo 题意: 给你一个有n个数的数列c1~cn,h1~hn为1~n的排列,求ci[hi>hi-1 and hi>hi+1]的期望和. ...
- LeetCode OJ 109. Convert Sorted List to Binary Search Tree
Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...
- PHP:urlencode
urlencode是用于对字符串进行编码,使得所有字符都能被放入url中,而不会被解析器误解. 正如html中的<>这样的符号是标记符,如果正文中存在<,要把它转义为< url ...
- mac中使用终端生成RSA私钥和公钥文件
1.打开终端输入:cd Desktop/ //进入桌面 2.OpenSSL //打开 OpenSSL 3.生成私钥pem, 执行命令 genrsa -out rsa_private_ke ...
- 使用PLSQL Developer连接Oracle Database 11g Express Edition
要使用oracle数据库,需要准备三部分: 1.oracle服务端 2.oracle客户端 3.连接工具 你装的Oracle Database 11g Express Edition就是服务端,pls ...
- 改良UIScrollView滚动视图
#define HEIGHT self.view.frame.size.height #define WIDTH self.view.frame.size.width @interface V ...
- Java学习笔记之类和对象
1.类是对象的抽象,对象是类的实例. 2.一个.java 文件,只能有一个公有类. 3.Java的默认访问权限是:default,即不加任何访问修饰符,该权限设置只能在同一包访问. 当前类 同一包 ...
- EL(表达式语言)
EL(Expression Language):目的是为了简化Jsp页面的语言,使页面看起来更加简洁 基本的语法特点 以“${"开头,以”}“结束 一 与低版本的环境兼容----禁用EL ( ...