<p>------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------</p>
<p> </p>
<p>笔记一共记录了毕向东的java基础的25天课程,分上、中、下</p>
<p>本片为中篇,涵盖11-20天课程</p>
11.线程
a.线程状态图
b 线程创建 继承 Thread 或者 实现Runnable接口
c 懒汉单例
public class Single {
private static Single s = null;
private Single(){ } public static Single getInstance(){
if(s == null){
synchronized (Single.class) {
if(s == null){
s = new Single();
}
}
}
return s;
}
}
d 线程死锁 同步中嵌套同步容易发生死锁
e 多线程运行安全问题
java解决方案:
同步代码块
同步的前提:
必须有两个或者两个以上的线程;必须是多个线程使用同一个锁
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,消耗资源
12.让线程锁一会儿吧
同步表现形式:
同步代码块;同步函数
同步代码块使用的锁是任意java对象;同步函数使用的锁是this;对应static的同步函数,使用的锁不是this。是类型.class该类的字节码文件。
当线程需要同时持有多个锁时,有可能产生死锁。考虑如下情形:
线程A当前持有互斥所锁lock1,线程B当前持有互斥锁lock2。接下来,当线程A仍然持有lock1时,它试图获取lock2,因为线程B正持有lock2,因此线程A会阻塞等待线程B对lock2的释放。如果此时线程B在持有lock2的时候,也在试图获取lock1,因为线程A正持有lock1,因此线程B会阻塞等待A对lock1的释放。二者都在等待对方所持有锁的释放,而二者却又都没释放自己所持有的锁,这时二者便会一直阻塞下去。这种情形称为死锁。
下面给出一个两个线程间产生死锁的示例,如下:
package com.itheima; public class DeadLock {
private String objID;
public DeadLock(String id){
objID = id;
} public synchronized void checkOther(DeadLock other){
print("entering checkOther");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO: handle exception
}
print("in checkOther() - about to " + "invoke 'other.action()'");
other.action();
print("leaving checkOther()");
} public synchronized void action() {
print("entering action()");
try { Thread.sleep(500); }
catch ( InterruptedException x ) { }
print("leaving action()");
} public void print(String msg) {
threadPrint("objID=" + objID + " - " + msg);
} public static void threadPrint(String msg) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + ": " + msg);
} public static void main(String[] args) {
final DeadLock obj1 = new DeadLock("obj1");
final DeadLock obj2 = new DeadLock("obj2"); Runnable runA = new Runnable() {
public void run() {
obj1.checkOther(obj2);
}
};
Thread threadA = new Thread(runA, "threadA");
threadA.start(); try { Thread.sleep(200); }
catch ( InterruptedException x ) { } Runnable runB = new Runnable() {
public void run() {
obj2.checkOther(obj1);
}
};
Thread threadB = new Thread(runB, "threadB");
threadB.start();
try { Thread.sleep(5000); }
catch ( InterruptedException x ) { } threadPrint("finished sleeping"); threadPrint("about to interrupt() threadA");
threadA.interrupt(); try { Thread.sleep(1000); }
catch ( InterruptedException x ) { } threadPrint("about to interrupt() threadB");
threadB.interrupt(); try { Thread.sleep(1000); }
catch ( InterruptedException x ) { } threadPrint("did that break the deadlock?");
threadPrint("no,已经发生了死锁");
}
}
如何在一个线程执行过程中加入另一个线程执行,并使当前线程等待。
join:当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。join可以用来临时加入线程执行。
调用线程run方法 和start方法的区别,看一段代码然后分析
class MyThread extends Thread{
public void run(){
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
}
System.out.println("MyThread running");
}
} public class ThreadTest{
public static void main(String argv[]) {
MyThread t = new MyThread();
t.run();
t.start();
System.out.println("Thread Test");
}
}
/*
代码分析过程:
MyThread t = new MyThread();
创建了一个线程。
t.run();
调用MyThread对象的run方法。
这是只有一个线程在运行就是主线程。
当主线程执行到了run方法中的sleep(3000);时。
这是主线程处于冻结状态。程序并没有任何执行。
当3秒过后,主线程打印了 MyThread running。 run方法执行结束。
t.start();
开启了t线程。
有两种可能情况。
第一种,主线程在只执行了t.start()后,还具有执行权,继续往下执行,
打印了Thread Test。主线程结束。
t线程获取执行权,调用自己的run方法。然后执行的sleep(3000);冻结3秒。
3秒后,打印MyThread running t线程结束,整个程序结束。
第二种情况:
主线程执行到t.start();开启了t线程,t线程就直接获取到了执行权。
就调用自己的run方法。
指定到sleep(3000).t线程冻结3秒,这是t线程就是释放了执行权。
那么主线程开始执行打印了Thread Test,主线程结束。
等到3秒后,t线程打印MyThread running ,然后t线程结束。
程序结束。
如何停止线程?
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构。
只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:
当线程处于了冻结状态。
就不会读取到标记。那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。
Thread类提供该方法 interrupt();
经典线程问题:生产者与消费者
对象分析:生产者-消费者-资源
资源涉及到同步
设计资源对象
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
// t1 t2
public synchronized void set(String name)
{
while(flag)
try{this.wait();}catch(Exception e){}//t1(放弃资格) t2(获取资格)
this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
this.notifyAll();
} // t3 t4
public synchronized void out()
{
while(!flag)
try{wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格)
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
this.notifyAll();
}
}
生产者对象
class Producer implements Runnable
{
private Resource res; Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.set("+商品+");
}
}
}
消费者对象
class Consumer implements Runnable
{
private Resource res; Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.out();
}
}
}
测试用例
class ProducerConsumerDemo
{
public static void main(String[] args)
{
Resource r = new Resource(); Producer pro = new Producer(r);
Consumer con = new Consumer(r); Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con); t1.start();
t2.start();
t3.start();
t4.start(); }
}
jdk1.5中提供的多线程升级解决方案:
Lock 和 Condition对象
import java.util.concurrent.locks.*; class ProducerConsumerDemo2
{
public static void main(String[] args)
{
Resource r = new Resource(); Producer pro = new Producer(r);
Consumer con = new Consumer(r); Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con); t1.start();
t2.start();
t3.start();
t4.start(); }
} /*
JDK1.5 中提供了多线程升级解决方案。
将同步Synchronized替换成现实Lock操作。
将Object中的wait,notify notifyAll,替换了Condition对象。
该对象可以Lock锁 进行获取。
该示例中,实现了本方只唤醒对方操作。 Lock:替代了Synchronized
lock
unlock
newCondition() Condition:替代了Object wait notify notifyAll
await();
signal();
signalAll();
*/
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
// t1 t2
private Lock lock = new ReentrantLock(); private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition(); public void set(String name)throws InterruptedException
{
lock.lock();
try
{
while(flag)
condition_pro.await();//t1,t2
this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
condition_con.signal();
}
finally
{
lock.unlock();//释放锁的动作一定要执行。
}
} // t3 t4
public void out()throws InterruptedException
{
lock.lock();
try
{
while(!flag)
condition_con.await();
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
condition_pro.signal();
}
finally
{
lock.unlock();
} }
} class Producer implements Runnable
{
private Resource res; Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.set("+商品+");
}
catch (InterruptedException e)
{
} }
}
} class Consumer implements Runnable
{
private Resource res; Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.out();
}
catch (InterruptedException e)
{
}
}
}
}
线程总结:
wait和sleep区别
wait:释放cpu执行权,释放同步中锁
sleep:释放cpu执行权,不释放同步中锁
停止线程:
stop过时。
原理:run方法结束。run方法中通常定义循环,指定控制住循环线程即可结束。
1,定义结束标记。
2,当线程处于了冻结状态,没有执行标记,程序一样无法结束。
这时可以循环,正常退出冻结状态,或者强制结束冻结状态。
强制结束冻结状态:interrupt();目的是线程强制从冻结状态恢复到运行状态。
但是会发生InterruptedException异常。
线程中一些常见方法:
setDaemon(boolean):将线程标记为后台线程,后台线程和前台线程一样,开启,一样抢执行权运行,
只有在结束时,有区别,当前台线程都运行结束后,后台线程会自动结束。
join():什么意思?等待该线程结束。当A线程执行到了B的.join方法时,A就会处于冻结状态。
A什么时候运行呢?当B运行结束后,A就会具备运行资格,继续运行。
加入线程,可以完成对某个线程的临时加入执行。
yield:临时暂停,可以让线程是释放执行权。
13.数据类型
基本数据类型 ,基本数据类型包装类 ,自动装箱拆箱,特殊类型字符串
Integer m = 128;
Integer n = 128;
print("m==n:"+(m==n));false 不同的对象引用
Integer a = 127;
Integer b = 127;
print(a == b);true //当数值在byte范围内(0-127),对于新特性,如果该数值已经存在,则不会在开辟新的空间。
String s1 = "abc";//s1是一个类类型变量, "abc"是一个对象。
//字符串最大特点:一旦被初始化就不可以被改变。
String s2 = new String("abc");
//s1和s2有什么区别?
//s1在内存中有一个对象。
//s2在内存中有两个对象。
String a = "opq";
String b = "opq";
System.out.println("a==b:"+(a==b)); true
/*
获取两个字符串中最大相同子串。第一个动作:将短的那个串进行长度一次递减的子串打印。
"abcwerthelloyuiodef"
"cvhellobnm"
思路:
1,将短的那个子串按照长度递减的方式获取到。
2,将每获取到的子串去长串中判断是否包含,
如果包含,已经找到!。
*/
public static String maxSubStr(String s1, String s2){
String maxSub = "";
//得到短的串
//对短的串依次遍历长度依次递减获取字串
String max = s1.length() >= s2.length() ? s1 : s2;
String min = max == s1 ? s2 : s1;
for (int i = 0; i < max.length(); i++) {
for(int j=0,k=min.length()-i ; k != min.length() +1 ; j++,k++){
maxSub = min.substring(j, k);
if(max.contains(maxSub)){
System.out.println("同时出现的最大字串:"+maxSub);
return maxSub;
}
}
}
return maxSub;
}
StringBuffer 字符串缓冲区
JDK1.5版本之后出现了StringBuilder
StringBuffer线程同步
StringBuilder线程不同步
开发建议使用StringBuilder
1.提高效率
2.简化书写
3.提高安全性
14.集合
/*
Collection
|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。
|--Set:元素是无序,元素不可以重复。、
List:
特有方法。凡是可以操作角标的方法都是该体系特有的方法。
增
add(index,element);
addAll(index,Collection);
删
remove(index);
改
set(index,element);
查
get(index):
subList(from,to);
listIterator();
int indexOf(obj):获取指定元素的位置。
ListIterator listIterator();
List集合特有的迭代器。ListIterator是Iterator的子接口。
在迭代时,不可以通过集合对象的方法操作集合中的元素。
因为会发生ConcurrentModificationException异常。
所以,在迭代器时,只能用迭代器的放过操作元素,可是Iterator方法是有限的,
只能对元素进行判断,取出,删除的操作,
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。
该接口只能通过List集合的listIterator方法获取。
*/
1,add方法的参数类型是Object。以便于接收任意类型对象。
2,集合中存储的都是对象的引用(地址)
|--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。、
|--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。
注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
|--TreeSet:
Set集合的功能和Collection是一致的。
15.泛型
泛型:JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。
好处
1.将运行时期出现问题ClassCastException,转移到了编译时期。,
方便于程序员解决问题。让运行时问题减少,安全。,
2,避免了强制转换麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。
在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,
只要见到<>就要定义泛型。
其实<> 就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
16.Map集合
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。
|--HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。
"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数。
希望打印结果:a(1)c(2).....
通过结果发现,每一个字母都有对应的次数。
说明字母和次数之间都有映射关系。
注意了,当发现有映射关系时,可以选择map集合。
因为map集合中存放就是映射关系。
因为打印结果的字母有顺序 核心就是说出使用treemap集合
17.数组操作工具类、集合操作工具类、静态导入
高级for循环
格式:
for(数据类型 变量名 : 被遍历的集合(Collection)或者数组)
{
}
对集合进行遍历。
只能获取集合元素。但是不能对集合进行操作。
迭代器除了遍历,还可以进行remove集合中元素的动作。
如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。
传统for和高级for有什么区别呢?
高级for有一个局限性。必须有被遍历的目标。
建议在遍历数组的时候,还是希望是用传统for。因为传统for可以定义脚标。
/*
JDK1.5版本出现的新特性。
方法的可变参数。
在使用时注意:可变参数一定要定义在参数列表最后面。
*/
18.日期类和文件操作
19. 文件包装类
装饰设计模式:
当想要对已有的对象进行功能增强时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象。
并基于被装饰的对象的功能,提供更强的功能。
20. 递归 ini文件 properties
SequenceInputStream
黑马程序员----java基础笔记中(毕向东)的更多相关文章
-
黑马程序员----java基础笔记上(毕向东)
------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 笔记一共记录了毕向东的java基础的25天课程,分上.中.下 本片为上篇,涵盖前10天课程 1. ...
-
黑马程序员----java基础笔记下(毕向东)
------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 目录--- 21.字符编码 22.javaswig 事件 23.socket 网络通讯 24.网 ...
-
黑马程序员Java基础班+就业班课程笔记全发布(持续更新)
正在黑马学习,整理了一些课程知识点和比较重要的内容分享给大家,也是给自己拓宽一些视野,仅供大家交流学习,大家有什么更好的内容可以发给我 ,现有黑马教程2000G QQ 1481135711 这是我总 ...
-
黑马程序员——JAVA基础之泛型和通配符
------- android培训.java培训.期待与您交流! ---------- 泛型: JDK1.5版本以后出现新特性.用于解决安全问题,是一个类型安全机制. 泛型好处: ...
-
黑马程序员——JAVA基础之简述面向对象,类,变量,匿名对象
------- android培训.java培训.期待与您交流! ---------- 面向对象: 面向对象是相对面向过程而言 面向对象和面向过程都是一种思想 面向过程 强调的是功能行为 面向对象 将 ...
-
黑马程序员——JAVA基础之语法、命名规则
------- android培训.java培训.期待与您交流! ---------- 1.java语言组成:关键字,标识符,注释,常量和变量,运算符,语句,函数,数组. 2.java关键字:被Jav ...
-
黑马程序员——JAVA基础之反射
------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- Java 反射是Java语言的一个很重要的特征,它使得Java具体了"动态 ...
-
黑马程序员 Java基础<;十八>;--->; 网路编程
--------------- ASP.Net+Android+IO开发S..Net培训.期待与您交流! --------------- 第一 概述 一.概述: 1.网络模型:OSI参考模型和TCP ...
-
纯干货!耗时1个月整理黑马程序员Java教程+笔记+配套工具
学习Java是不是很苦?找不到资料?不了解学习步骤?想要全面的线路图! 或者是找资料,前面免费,后面收费?工具软件要收费? 当当当~~今天就没有这个状态发生了!不信就证明给你看 1.学习路线图 2.J ...
随机推荐
-
cat命令
[cat] 合并文件和打印到标准输出 命令格式: cat [OPTION]... [FILE]... 命令功能: 拼接文件或者做标准输入输出 命令格式: cat [OPTION].. ...
-
IE不能上网,但是其他浏览器可以
打开IE_工具_internet选项_连接_局域网设置_(勾选)自动检测配置其它的勾去掉,确定.
-
eclipse/intellij idea 远程调试hadoop 2.6.0
很多hadoop初学者估计都我一样,由于没有足够的机器资源,只能在虚拟机里弄一个linux安装hadoop的伪分布,然后在host机上win7里使用eclipse或Intellj idea来写代码测试 ...
-
申请UAC权限Manifest文件
申请UAC 高级权限用, 同时不会影响系统风格 <?xml version="1.0" encoding="UTF-8" standalone=" ...
-
笔记5:QQ群聊天机器人
之前经常在别人群里看到有自动回复消息的机器人. 功能有好多,可以玩各种游戏.觉得还蛮有意思的.. 于是就去请教别人怎么弄得,但是他们都说得好复杂,好高大上,无非就是不想让别人弄 本人是个不会轻易放弃的 ...
-
cg 到hlsl的转换
http://msdn.microsoft.com/en-us/library/windows/desktop/ff471376(v=vs.85).aspx http://gamedev.stacke ...
-
Match+Faq
假如在GameLayer.h中有Card类型的变量,那么在Card.h文件中,不要有GameLayer.h的导入.这样子会导致编译器找不到对Card类型的定义而导致报错.但是,在Card.cpp中可以 ...
-
ARM Cortex M3系列GPIO口介绍(工作方式探讨)
一.Cortex M3的GPIO口特性 在介绍GPIO口功能前,有必要先说明一下M3的结构框图,这样能够更好理解总线结构和GPIO所处的位置. Cortex M3结构框图 从图中可以看出 ...
-
移动开发中使用的一些meta头部标签整理
<!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --> <html lang="zh-cmn-Hans"&g ...
-
Media Session API 为当前正在播放的视频,音频,提供元数据来自定义媒体通知
google 文档 https://developers.google.cn/web/updates/2017/02/media-session <html lang="zh-cmn- ...