JAVA自学笔记23
JAVA自学笔记23
1、多线程
1)引入:
2)进程
是正在运行的程序。是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。
多进程:
单进程的计算机只能做一件事情,而现在的计算机都可以做多件事情。CPU在某个时间点上只能做一件事。每一个进程都有它自己的内存空间和系统资源。
3)多线程
-是进程中的单个顺序控制流,是一条执行路径
-一个进程如果只有一条执行路径,则称为单线程程序。一个进程如果有多条执行路径,称为多线程程序。
4)并行与并发
前者是逻辑上同时发生,指在某一个时间段内同时运行多个程序;后者是物理上同时发生,指在,某一个时间点内同时运行多个程序
5)Java程序运行原理
java命令会启动java虚拟机,启动jvm,等于启动了一个应用程序,也就是启动了一个进程,该进程会自动地启动一个“主线程”,然后主线程去调用某个类的main方法,所以main方法运行在主线程中。在此之前的所有程序都是单线程的。
JVM的启动时单线程还是多线程的呢?
多线程的。垃圾回收线程也要先启动,否则很容易出现内容溢出。最少都启动了两个线程。
创建新执行线程有两种方法,一种方法时将类声明为Thread的子类。该子类应重写Thread类的run方法。接下来可以分配并启动该子类的实例。
即-自定义一个继承自Thread的类
-重写run()方法(不是类中的所有代码都需要被线程执行。此时,为了区分哪些代码能够被执行。java提供了Thread类中的run()方法用于包含那些被执行的代码。)
-创建对象
-启动线程
另一种方法是声明实现Runnable接口的类,该类然后实现run方法,然后就可以分配该类的实例。start()方法:使该线程开始执行,Java虚拟机调用该线程的run方法。它和run()的区别是run()仅仅是封装被线程执行的代码,直接调用的是普通方法start()首先启动了线程,然后再由jvm去调用该线程的run()方法。
//多线程的实现
//方式1
public class MyThread extends Thread{
public void run(){
//一般来说,被线程执行的代码肯定是比较耗时的
for(int x=0;x<10000;x++){
System.out.println("cc"+x);
}
}
}
//测试类
public class MyThreadDemo{
public static void main (String[] args){
//创建线程对象
MyThread my1=new MyThread();
MyThread my2=new MyThread();
//启动线程
my1.start();
my2.start();
}
}
5)获取和设置线程对象的名称
获取:
public final String getName(); //程序将输出Thread-?,?按顺序从0开始
设置
public final void setName(String name);
public class MyThread extends Thread{
//无参构造
public MyThread(){}
//带参构造
public MyThread(String name){
super(name);
}
public void run(){
//一般来说,被线程执行的代码肯定是比较耗时的
for(int x=0;x<10000;x++){
System.out.println("getName()+cc"+x);
}
}
}
//创建线程对象
MyThread my1=new MyThread();
MyThread my2=new MyThread();
//设置名称
my1.setName("cc");
my2.setName("dd");
//启动线程
my1.start();//Thread-0
my2.start();//Thread-1
}
}
//带参构造
MyThread my1=new Mythread("许先生");
MyThread my1=new Mythread("刘先生");
//获取main方法对应线程的名称
//public static Thread currentThread()
返回当前正在执行的线程对象
System.out.println(Thread currrentThread().getName());
6)线程调度
①分时调度模型:
所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
②抢占式调度模型 优先让优先级高的线程使用CPU。如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些。Java使用此类模型
设置优先级的方法:
public final void setPriority (newPriority)
MAX_PRIORITY=10
MIN_PRIORITY=1
NORM_PRIORITY=5
获取线程对象的优先级,默认优先级是5:
public final int getPriority()
public class ThreadPriority extends Thread{
public void run(){
//一般来说,被线程执行的代码肯定是比较耗时的
for(int x=0;x<10000;x++){
System.out.println("getName()+cc"+x);
}
}
}
public class ThreadPriorityDemo{
public static void main(String args[]){
ThreadPriority tp1=new ThreadPriority();
ThreadPriority tp2=new ThreadPriority();
ThreadPriority tp3=new ThreadPriority();
tp1.setName("aa");
tp2.setName("bb");
tp3.setName("cc");
tp1.getPriority();
tp2.getPriority();
tp3.getPriority()
tp1.setPriorty(8);//存在随机性
tp1.start();
tp2.start();
tp3.start();
}
}
7)线程控制
线程休眠
public static void sleep(long mills)
在指定毫秒内让当前正在执行的线程休眠
线程加入
public final void join()
等待该线程终止
public class ThreadJoin extends Thread{
public void run(){
for(int x=0;x<10000;x++){
System.out.println("getName()+cc"+x);
}
}
}
public class ThreadJoinDemo{
public static void main(String args[]){
ThreadJoin tp1=new ThreadJoin();
ThreadJoin tp2=new ThreadJoin();
ThreadJoin tp3=new ThreadJoin();
tp1.setName("aa");
tp2.setName("bb");
tp3.setName("cc");
tp1.start();
tp1.join();
tp2.start();
tp3.start();
}
}
线程礼让
public static void yield()
public class ThreadJoin extends Thread{
public void run(){
for(int x=0;x<10000;x++){
System.out.println("getName()+cc"+x);
Thread.yield();
}
}
}
public class ThreadYieldDemo{
public static void main(String args[]){
ThreadYield tp1=new ThreadYield();
ThreadYield tp2=new ThreadYield();
tp1.setName("aa");
tp2.setName("bb");
tp1.start();
tp2.start();
}
}
后台线程
public final void setDaemon(boolean on)
将该线程标记为守护线程或用户线程,当正在运行的线程都是守护线程时,jvm退出。必须在启动线程前调用。
中断线程
public final void stop()//已过时但仍可使用,具有不安全性
public void interrupt()//把线程状态终止,并抛出InterruptedException 异常
public class ThreadStop extends Thread{
public void run(){
System.out.println("开始执行:"+new Date());
}
}
public class ThreadStopDemo{
public static void main(String args[]){
ThreadStop ts=new ThreadStop();
ts.start();
Thread.sleep(3000);
//ts.stop();
ts.intereupt();
}
}
8)线程生命周期图解:
9)多线程的实现方案2
①好处:可以避免由于java单继承而带来的局限性。适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好地体现; 面向对象的设计思想。
-自定义类MyRunnable实现Runnable接口
-重写run()方法
-创建MyRunnable类的对象
-创建Thread类的对象,作为上一步骤的参数传递
public class MyRunnable implements Runnable{
public void run(){
for(int x=0;x<100){
System.out.println(Thread.currentThread.geiName()+":"+x);
}
}
}
public class MyRunnableDemo{
public static void main(String args[]){
MyRunnable my=new MyRunnable();
//Thread t1=new Thread(my,"cc");
//Thread t2=new Thread(my,"dd");
Thread t1=new Thread(my);
Thread t2=new Thread(my);
t1.setName("cc");
t1.setName("dd");
t1.start();
t2.start();
}
}
②两种方式的比较图解
@例题1:售卖电影票
public class SellTicketDemo{
public static void main(String args[]){
SellTicket st1=new SelTicket();
SellTicket st2=new SelTicket();
SellTicket st3=new SelTicket();
st1.setName("窗口1");
st2.setName("窗口2");
st3.setName("窗口3");
st1.start();
st2.start();
st3.start();
}
}
public class SellTicket extends Thread{
public void run(){
private static int tickets=100;
public void run(){
while(true){
if(tickets>0){
System.out.println(getName()+"正在售出第"+(tickets--)+"张票");
}
}
}
}
}
//第二种方式
public class SellTickets implements Runnable{
private int tickets=100;
public void run(){
while(true){
if(tickets>0){
System.out.println(getName()+"正在售出第"+(tickets--)+"张票");
}
}
}
}
public class void main(String args[]){
SellTicket st=new SellTicket();
Thread t1=new Thread(st,"窗口1");
Thread t2=new Thread(st,"窗口2");
Thread t1=new Thread(st,"窗口3");
t1.start();
t2.start();
t3.start();
}
改进每次售出一张票延迟0.1秒
//第二种方式
public class SellTickets implements Runnable{
private int tickets=100;
//创建锁对象
private Object obj =new Object();
public void run(){
synchronized(obj){
while(true){
if(tickets>0){
Thread.sleep(1000);
System.out.println(getName()+"正在售出第"+(tickets--)+"张票");
}}
}
}
}
public class void main(String args[]){
SellTicket st=new SellTicket();
Thread t1=new Thread(st,"窗口1");
Thread t2=new Thread(st,"窗口2");
Thread t1=new Thread(st,"窗口3");
t1.start();
t2.start();
t3.start();
}
出现了问题:
①相同号码的票售出多次
②出现了负数序号的票
CPU的每一次执行必须是一个原子性(最简单基本的)操作。是由于随机性和延迟导致的
利用同步块的方式解决上述问题
同步代码块:
格式:synchronized(对象)(需要同步的代码;)
可以解决安全问题,其对象可以是任何对象。
把多条语句操作共享数据的部分给包起来
同步的好处与弊端:
好处:同步的出现解决了多线程的安全问题
弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,非常耗费系统资源
前提:多个线程使用同一把锁
同步方法:把同步关键字加载到方法上
A:同步代码块的锁对象是谁呢?
* 任意对象。
*
* B:同步方法的格式及锁对象问题?
* 把同步关键字加在方法上。
*
* 同步方法是谁呢?
* this
*
* C:静态方法及锁对象问题?
* 静态方法的锁对象是谁呢?
* 类的字节码文件对象。(反射会讲)
//再次改进
public class SellTicketDemo {
public static void main(String[] args) {
// 创建资源对象
SellTicket st = new SellTicket();
// 创建三个线程对象
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
}
package cn.itcast_11;
public class SellTicket implements Runnable {
// 定义100张票
private static int tickets = 100;
// 定义同一把锁
private Object obj = new Object();
private Demo d = new Demo();
private int x = 0;
@Override
public void run() {
while (true) {
if(x%2==0){
synchronized (SellTicket.class) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
}else {
private static synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
}
8)线程安全的类
StringBuffered
Vector
Hashtable
collections下有很多线程安全的类
JAVA自学笔记23的更多相关文章
- JAVA自学笔记06
JAVA自学笔记06 1.二维数组 1)格式: ①数据类型[][]数组名 = new 数据类型[m][n]; 或 数据类型[]数组名[]=new 数据类型[m][n]; m表示这个二维数组有多少个一维 ...
- JAVA自学笔记15
JAVA自学笔记15 @例题1:共有5个学生,请把五个学生的信息存储到数组中,并遍历数组,并获取每个学生的信息 Students[] students=new Student[5]; Student ...
- JAVA自学笔记18
JAVA自学笔记18 1.Map接口: 1)功能: 2) Map<String,String>m=new HashMap<String,String>(); //添加元素,元素 ...
- JAVA自学笔记24
JAVA自学笔记24 1.能使用同步代码块就使用同步代码块,除非锁对象是this,就可以考虑使用同步方法.静态方法的锁是类的字节码对象. 2.JDK5新特性 1)接口Lock void Lock()/ ...
- JAVA自学笔记09
JAVA自学笔记09 1.子类的方法会把父类的同名方法覆盖(重写) 2.final: 1)可修饰类.方法.变量 2)修饰类时:此时该类变为最终类,它将无法成为父类而被继承 3)修饰方法时:该方法将无法 ...
- JAVA自学笔记05
JAVA自学笔记05 1.方法 1)方法就是完成特定功能的代码块,类似C语言中的函数. 2)格式: 修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2,-){ 函数体; return ...
- JAVA自学笔记04
JAVA自学笔记04 1.switch语句 1)格式:switch(表达式){ case 值1: 语句体1; break; case 值2: 语句体2; break; - default: 语句体n+ ...
- JAVA自学笔记07
JAVA自学笔记07 1.构造方法 1) 例如:Student s = new Student();//构造方法 System.out.println(s);// Student@e5bbd6 2)功 ...
- JAVA自学笔记10
JAVA自学笔记10 1.形式参数与返回值 1)类名作为形式参数(基本类型.引用类型) 作形参必须是类的对象 2)抽象类名作形参 需要该抽象类的子类对象,通过多态实现 3)接口名为形参 需要的是该接口 ...
随机推荐
- django引入现有数据库 转
django引入现有数据库 Django引入外部数据库还是比较方便的,步骤如下: 1.创建一个项目,修改seting文件,在setting里面设置你要连接的数据库类型和连接名称,地址之类,和创建新 ...
- 禁止root直接登陆linux系统
直接修改文件 # vim /etc/ssh/sshd_config SyslogFacility AUTHPRIV PermitRootLogin no RSAAuthentication yes P ...
- net core体系-web应用程序-4asp.net core2.0 项目实战(1)-7项目缓冲方案( Redis)
本文目录1. 摘要2. Redis配置3. RedisHelper4.使用实例 5. 总结 1. 摘要 由于內存存取速度远高于磁盘读取的特性,为了程序效率提高性能,通常会把常用的不常变动的数据存储在 ...
- js网页下载csv格式的表格
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- BZOJ2553 [BeiJing2011]禁忌 AC自动机 矩阵
原文链接http://www.cnblogs.com/zhouzhendong/p/8196279.html 题目传送门 - BZOJ2553 题意概括 引用一下lych大佬的: 在字母只有前alph ...
- js获取背景颜色
//js获取背景颜色var Airport=$("#Airport").css('background-color'); js设置背景颜色 $("#intercity&q ...
- 20165235 2017-2018-2《Java程序设计》课程总结
20165235 2017-2018-2<Java程序设计>课程总结 每周作业链接汇总 预备作业一 预备作业二 预备作业三 第一周学习总结 第二周学习总结 第三周学习总结 第四周学习总结 ...
- Mybatis关联一对多映射不能查询出所有的数据的问题
在使用Mybatis进行一对多查询时,如果返回的是一个对象的话,可以发现将一对多的数据全都取出来了,但是这样的缺点是有很多值为null,我们更喜欢将返回值设为Map的形式,这样可以去除那些多余null ...
- Codeforces 861D - Polycarp's phone book 【Trie树】
<题目链接> 题目大意: 输入7e4个长度为9的字符串,每个字符串中只出现0~9这几种数字,现在需要你输出每个母串中最短的特有子串. 解题分析: 利用Trie树进行公共子串的判定,因为Tr ...
- P1938 [USACO09NOV]找工就业Job Hunt
P1938 [USACO09NOV]找工就业Job Hunt给边赋予价值,入边的权值为D-Ti,然后从起点开始跑最长路,如果钱的总数超过了D*C,也就是一定有一个城市走了两遍,则有正环,则输出-1 # ...