笔记-迎难而上之Java基础进阶4
内部类创建多线程
//匿名内部类创建多线程
public class InnerClassThread{
public static void main(String[] args){
//回忆一下之前创建多线程的过程
//先创建一个Thread的子类,通过这个子类,重写run方法
//创建子类的对象.通过子类对象调用 start();方法开启多线程
//现在试一下匿名内部类创建多线程
new Thread(){
public void run(){
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
}.start();
//之前通过Runnable开启多线程的步骤
//创建一个Runnable的实现类,创建这个实现类的对象
//通过线程的构造方法传递实现类对象,开启线程
Runnable r = new Runnable(){
public void run(){
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"---"+"程序员");
}
}
};
new Thread(r).start();
}
}
多线程的安全问题
//实现Implements接口,是开启多线程的前提
public class TicketDemo implements Runnable {
int ticket = 100;
public void run() {
while(true){
if(ticket>0){
try{
Thread.sleep(10);
}catch(Exception e){
e.printStackTrace();
}
//需要看一看是那一条线程抢到CPU的执行权
System.out.println("我是"+Thread.currentThread().getName()+"正在出售第"+ticket+"票");
ticket--;
}
}
}
}
public class TicketObject{
public static void main(String[] args){
TicketDemo td = new TicketDemo();
//传递实现implement接口的对象
Thread t1 = new Thread(td);
Thread t2 = new Thread(td);
Thread t3 = new Thread(td);
t1.setName("吕布");
t2.setName("典韦");
t3.setName("关羽");
//开线程,让他们互相抢夺CPU
t1.start();t2.start();t3.start();
}
}
这里出现了0,-1的票,出现了线程安全问题
线程安全问题的解决方法_同步代码块
格式:
synchronized(锁对象){
共享数据的代码
}
注意事项:
- 通过代码块中的所对象,可以使用任意的对象
- 但是必须保证多个线程使用同一个对象
- 锁对象的作用是把同步代码块锁住,只让一个线程在同步代码块中执行
//就在共享数据里加一个synchronized同步代码块就可以解决多线程的安全问题了
while(true){
synchronized(obj){
if(ticket>0){
try{
Thread.sleep(10);
}catch(Exception e){
e.printStackTrace();
}
//需要看一看是那一条线程抢到CPU的执行权
System.out.println("我是"+Thread.currentThread().getName()+"正在出售第"+ticket+"票");
ticket--;
}
}
}
同步代码块的原理
使用了同一个锁对象,这个锁对象叫做同步锁,
3个线程一起抢夺cpu的执行权,谁抢到谁执行run方法进行卖票
吕布抢到了cpu的执行权就会执行run方法,遇到synchronized代码块,这个时候吕布会检查synchronized代码块是否有锁对象,有就会进入到同步中执行,如果没有就等待,不进入同步
当执行完了同步代码块的程序就会归还锁对象,
总结:同步中的线程,没有执行完毕不会释放锁,同步外的线程没有锁进不去同步
并发与并行
并发:是指cpu在同一个时间段内执行多个任务,交替执行任务
并行:是指cup在同一个时刻执行多个任务,一下执行多个任务
解决线程安全问题_Lock锁
使用步骤:
在成员位置创建一个ReentrantLock对象
在可能会出现安全问题的代码钱调用Lock接口中的方法lock获取锁
在可能出现安全问题的代码后调用lock接口中的方法unlock释放锁
Lock l = new ReentrantLock();
public void run() {
while(true){
l.lock();
if(ticket>0){
try{
Thread.sleep(10);
//需要看一看是那一条线程抢到CPU的执行权
System.out.println("我是"+Thread.currentThread().getName()+"正在出售第"+ticket+"票");
ticket--;
}catch(Exception e){
e.printStackTrace();
}finally{
l.unlock();
}
线程的等待唤醒机制
什么是等待机制?
一个线程进行了规定操作后,就进入等待状态wait,等待其他线程执行完他们的指定代码过后,再将其唤醒notify,
wait:线程不在活动,不在参与调度
notify:线程会唤醒正在wait的线程
注意事项
- wait方法与notify方法必须要由同一个锁对象调用,因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程
- wait方法与notify方法属于Object类的方法
- wait方法与notify方法必须要做同步代码块或者同步函数中使用
public class BaoZi {
//包子是包子铺跟吃货的共享资源
String pi;
String xian;
boolean flag = false;
}
//包子铺是一个线程类,生产包子,但是包子不能够生产太快(就是不可以让cpu全部被他占用了),
// 包子过多,不会吃不完,所以需要一个等待与唤醒机制
public class BaoZipu extends Thread{
private BaoZi bz;
public BaoZipu(BaoZi bz) {
this.bz = bz;
}
public void run() {
//重写run方法,设置线程任务,任务是生产包子
int count = 0;
while (true) {
synchronized (bz) {
//如果有包子,就等待,不需要生产包子
if (bz.flag == true) {
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//没有包子,就生产包子
if (count % 2 == 0) {
bz.pi = "剥皮";
bz.xian = "三鲜馅";
} else {
bz.pi = "冰皮";
bz.xian = "牛肉大葱馅";
}
count++;
System.out.println("包子铺正在生产:" + bz.pi + bz.xian + "包子");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//包子有了有就改为true状态
bz.flag = true;
//唤醒另外一条线程
bz.notify();
System.out.println("包子铺已经生产好了:" + bz.pi + bz.xian + "包子");
}
}
}
}
public class ChiHuo extends Thread{
private BaoZi bz;
public ChiHuo(BaoZi bz){
this.bz = bz;
}
public void run(){
//重写run方法,设置线程任务,任务是吃包子
while(true){
synchronized (bz){
//没有包子,就等待包子的产生
if(bz.flag==false){
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有包子就吃包子
System.out.println("吃货正在吃:"+bz.pi+bz.xian+"包子");
//吃完包子就把flag设置为false
bz.flag=false;
//唤醒线程另外一条线程
bz.notify();
System.out.println("吃货已经把:"+bz.pi+bz.xian+"的包子吃完了");
System.out.println("-------------");
}
}
}
}
public class Demo {
public static void main(String[] args) {
BaoZi bz = new BaoZi();
//开启线程,执行run方法
new BaoZipu(bz).start();
new ChiHuo(bz).start();
}
}
进入TimeWaitting(等待计时)的两种方式
- 使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到runnable/bloked状态
- 使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动进入Runnable/Blocked状态
线程池
线程池就是一个容器,可以使用集合来创建(ArrayList,HashSet,LinkedList,HashMap)
当我们需要使用线程时可以从线程池中通过remove等方法取出来
取出来后还可以返回去,通过add方法
但是在JDK1.5之后提供了一个创建线程池的工厂类,用来生成线程池
java.util.concurrent.Executors:线程池的工厂类
Executors类中的静态方法:static ExcecutorService newFixedThreadPool(int nThreads) 创建一个可以重用固定线程数的线程池
参数:int nThreads:创建线程池中包含的线程数量
返回值:ExecutorService接口,返回的就是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口接收
线程池的使用步骤:
- 使用线程池的工厂类Executors里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池
- 创建一个类,实现Runnable接口
- 调用ExecutorService中的方法submit,传递线程任务
- 调用ExecutorService中的方法shutdown销毁线程池
线程池的代码实现,
//创建Runnable接口实现类,因为等下一下的submit();方法会使用到它
public class RunnableRun implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName()+"");
}
}
import java.util.concurrent.*;
public class ThreadPool{
public static void main(String[] args){
//创建线程池工厂,通过类Executors的方法newFixedThreadPool();
//该类返回一个ExecutorService接口的实现类对象
ExecutorService es = Executors.newFixedThreadPool(2);
//使用ExecutorService类的方法submit()来开启线程
//submit类需要传递一个Runnable接口的实现类对象
//返回的结果是线程执行的任务
es.submit(new RunnableRun());
es.submit(new RunnableRun());
es.submit(new RunnableRun());
es.submit(new RunnableRun());
}
}
Lambda表达式
面向对象的思想:
做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情
函数式编程思想:
只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程
体验Lambda的更优写法
public class LambdaDemo{
public static void main(String[] args){
//匿名内部内创建多线程
new Thread(new Runnable(){
public void run(){
System.out.println(Thread.currentThread().getName()+"线程名称");
}
}).start();
//Lambda表达式创建多线程
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"线程名称");
}
).start();
}
}
Lambda标准格式
Lambda表达式的标准格式:
由三部分组成: a.一些参数 b.一个箭头 c.一段代码
格式:(参数列表) -> {一些重写的代码}
解析:
();接口中抽象方法的参数列表,没有参数,就空着,由参数就写参数
-> :传递的意思,把参数传递给方法体{}
();重写接口中的抽象方法的方法体
剩下几个Lambda表达式f的练习明天更……
笔记-迎难而上之Java基础进阶4的更多相关文章
- 笔记-迎难而上之Java基础进阶1
Collection集合 数组的长度是固定的,集合的长度是可变的 数组中存储的是同一类型的元素,可以存储基本数据类型值.集合存储的都是对象.而且对象的类型可以不一致. 集合框架 import java ...
- 笔记-迎难而上之Java基础进阶-终
使用Stream流的方式,遍历集合 import java.util.*; public class StreamDemo{ public static void main(String[] args ...
- 笔记-迎难而上之Java基础进阶8
函数式接口 函数式接口:有且只有一个抽象方法的接口,(可以包含其他默认,静态,私有方法) //函数式接口的使用,创建一个函数式接口 public interface FunctionalInterfa ...
- 笔记-迎难而上之Java基础进阶7
序列化流 把对象以流的方式写入到文件中保存,叫做对象的序列化 把文件中保存的对象,以流的方式读取出来,叫做对象大反序列化 对象的序列化流_ObjectOutputtream继承自OutputStrea ...
- 笔记-迎难而上之Java基础进阶2
Set集合 import java.util.*; public class HashSetDemo{ public static void main(String[] args){ //Set接口的 ...
- 笔记-迎难而上之Java基础进阶3
统计字符串中每一个不同的字符 import java.util.*; //统计字符串每一个字符出现的字数 public class StringDemo{ public static void mai ...
- 笔记-迎难而上之Java基础进阶6
import java.io.*; public class InputStreamDemo{ public static void main(String[] args) throws IOExce ...
- 笔记-迎难而上之Java基础进阶5
Lambda表达式无参数无返回值的练习 //定义一个接口 public interface Cook{ public abstract void makeFood(); } public class ...
- 第二十八节:Java基础-进阶继承,抽象类,接口
前言 Java基础-进阶继承,抽象类,接口 进阶继承 class Stu { int age = 1; } class Stuo extends Stu { int agee = 2; } class ...
随机推荐
- [solution]腾讯TEG_计算广告组_算法题
度娘笔试归来,题目实打实的,感觉真心不易,上百号人就抢那么几个坑......只恨自己平时积累太少啊~ 故曝一道鹅厂面试用的算法题(当时我就死在了这题上),来为度娘家攒一下RP~ 题目: 对于长度为N的 ...
- try_except__异常处理
try...except.raise 一.try...except 有时候我们写程序的时候,会出现一些错误或异常,导致程序终止.例如,做除法时,除数为0,会引起一个ZeroDivisionError ...
- Linux对大容量硬盘分区
随着单块硬盘容量的增大和硬盘价格的下降,2TB的磁盘使用将很快会普及,由于传统的MBR方式存储分区表的方 式缺陷,将可能导致很多分区工具不能正确地读取大于2TB容量的硬盘而无法正常分区大容量硬盘.其实 ...
- Android兼容性测试CTS --环境搭建、测试执行、结果分析
为了确保Android应用能够在所有兼容Android的设备上正确运行,并且保持相似的用户体验,在每个版本发布之时,Android提供了一套兼容性测试用例集合(Compatibility Test S ...
- Phonegap环境配置和安装插件
一:安装好jdk(配置好环境变量) 二:安装好Android SDK(配置好环境变量path F:\Android\android-sdk-windows\platform-tools;F:\Andr ...
- CodeForces 379F 树的直径 New Year Tree
题意:每次操作新加两个叶子节点,每次操作完以后询问树的直径. 维护树的直径的两个端点U,V,每次计算一下新加进来的叶子节点到U,V两点的距离,如果有更长的就更新. 因为根据树的直径的求法,若出现新的直 ...
- 【Jenskins】安装与配置
Jenskins教程:http://www.yiibai.com/jenkins/ 一.Jenskins的安装 1.jenskins下载和启动 Jenskins下载地址:https://jenkins ...
- grunt-nodemon参数配置
grunt-nodemon参数配置 nodemon0.2.0版本后参数名称做了较大改动,调整了下nodemon的参数配置,有需要的同学可以参考下: 1 2 3 4 5 6 7 8 9 10 11 12 ...
- LR采用的Sigmoid函数与最大熵(ME) 的关系
LR采用的Sigmoid函数与最大熵(ME) 的关系 从ME到LR 先直接给出最大熵模型的一般形式,后面再给出具体的推导过程. \[\begin{align*} P_w(y|x) &= \df ...
- Tomcat 禁用PUT方法, 404/500错误重定向, 网站图标
(1) Tomcat禁用Put等不安全方法. <security-constraint> <web-resource-collection> <web-resource- ...