??xml version="1.0" encoding="utf-8" standalone="yes"?> Z提高下蝲速度Q这里将Ubuntu的源改ؓ国内的源(以阿里源Z)Q?/p> 在配|文件中开头添加以下内?阉K?Q?/p> 执行命o更新一下: 首先需要安装一些必要的依赖Q?/p> 国内GO语言安装包的下蝲地址? 接下来配|GO的环境变量: 在文本中d以下内容: 执行命oQ?/p> 如果可以看到GO的版本信息,说明GO已经安装完成?/p> 在这里,我们可以使用阉K云的镜像地址安装Docker?br style="margin: 0px; padding: 0px;" />如果Ubuntupȝ中有旧版本的DockerQ需要卸载后重新安装?/strong>可以使用以下命oq行卸蝲Q?/p> 然后执行以下命o安装DockerQ?/p> 当前用h加到Docker用户l: docker镜像更改为阿里云的地址Q?br style="margin: 0px; padding: 0px;" />q一步只限Ubuntu16.04+,Debian8+,CentOS 7的系l?/strong> 对于Ubuntu14.04,Debian 7的系l,使用以下Ҏ更改镜像地址Q?br style="margin: 0px; padding: 0px;" />~辑 最后重启服务: 执行 首先需要安装Python pipQ?/p> 下蝲docker-compose的二q制包: 如果以上步骤可以利完成的话Q接下来可以进入正题了Q?/p> 首先创徏文g?/p> 从github上拉取fabric的源?/p> 如果上一步操作下载二q制文g太慢或者没速度Q可以直接对源码q行~译,执行以下命o(前提是以上相兌\径配|没有错?Q?/p> 生成的文gdq环境变?/p> 完成上面的操作,可以启动第一个fabric|络了?/p> 如果最后输出内容ؓ 说明我们的fabric|络已经成功搭徏完毕?/p> 补充一?/strong> 下一文章将详细讲解fabric|络的搭E?br style="margin: 0px; padding: 0px;" />传送门深入解析Hyperledger Fabric启动的全q程
在Java中通过ObservablecdObserver接口实现了观察者模式。一个Observer对象监视着一个Observable对象的变化,当Observable对象发生变化ӞObserver得到通知Q就可以q行相应的工作?/span>
如果画面A是显C数据库里面的数据,而画面B修改了数据库里面的数据,那么q时候画面Ap重新Load。这时候就可以用到观察者模?/span>
java.util.Observable中有两个Ҏ对Observer特别重要
①setChanged()Ҏ
setChanged()Ҏ
—? 用来讄一个内部标志位注明数据发生了变?/span> notifyObservers()Ҏ
/ notifyObservers(Object data)Ҏ —? 通知所有的Observer数据发生了变化,q时所有的Observer会自动调用复写好?span style="font-family:Arial; font-size:14px; color:#333333; line-height:21px">update(Observable
observable, Object data)Ҏ来做一些处理(比如说画面数据的更新Q?/span> 我们可以看到通知Observer有两个方法,一个无参,一个有参。那么这个参数有什么作用呢Q?/span> 其中一个作用:现在我不想通知所有的ObserverQ而只惛_中一个指定的Observer做一些处理,那么可以传一个参C为IDQ然后在所有的Observer中判断,每个Observer判断只有接收到底参数ID是属于自q才做一些处理?/span> 当然参数q有其他作用Q我只是举了个例子?/span> 下面举个例子加以说明Q?br /> 然后在setData()Ҏ里面Q也是数据改变的地方,来调用ObservablecȝsetChanged()Ҏ和notifyObservers()ҎQ表C数据已改变q知所有的Observer调用它们的update()Ҏ做一些处理?/p> 注意Q?span>只有在setChange()被调用后QnotifyObservers()才会去调用update()Q否则什么都不干?/span> 然后q要复写update()ҎQ做数据改变后的一些处理?/p> 下面可以写一个简单的试cL试一?/p> 属?—?br /> Ҏ —?span style="color:#ff0000">
1、编辑launch.json文g
// 使用 IntelliSense 了解相关属性?nbsp;
// 悬停以查看现有属性的描述?br />
// Ʋ了解更多信息,误? https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "debug",
"type": "go",
"request": "launch",
"mode": "debug",
"port": 8899,
"host": "127.0.0.1",
"program": "/Users/tingfeng/Workspace/go/src/github.com/nsharecome/caccount/main.go",
"env": {},
"args": [ ],
"output": "${workspaceRoot}/bin/debug_caccount",
"showLog": true
},
]
}
2、点击运行,报错如下Q?br />
could not launch process: decoding dwarf section info at offset 0x0: too short
Process exiting with code: 1
错误原因如下Q?a title="安装delve">安装delve
解决方式Q?br />
go get -u github.com/derekparker/delve/cmd/dl
利用delve手动调试可以参考:
]]>
]]>
?/p>1.搭徏Fabric的前|条?/h2>
#首先q行配置文g的备?/span> sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak #~辑配置文g sudo vim /etc/apt/sources.list
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
sudo apt-get update sudo apt-get upgrade
1.1安装GOLANG
sudo apt install libtool libltdl-dev
https://studygolang.com/dl
本文中下载了go1.12.5.linux-amd64.tar.gz
到Ubuntupȝ中?br style="margin: 0px; padding: 0px;" />压~包复制?code style="margin: 1px 5px; padding: 0px 5px !important; line-height: 1.8; vertical-align: middle; display: inline-block; font-family: "Courier New", sans-serif !important; font-size: 12px !important; background-color: #f5f5f5 !important; border: 1px solid #cccccc !important; border-radius: 3px !important;">/usr/local路径?执行以下命oq行解压Q?/p>cd /usr/local tar zxvf go*.tar.gz
sudo vim ~/.profile
export PATH=$PATH:/usr/local/go/bin export GOROOT=/usr/local/go export GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin
source ~/.profile go version
1.2安装Docker
sudo apt-get remove docker \ docker-engine \ docker.io
# step 1: 安装必要的一些系l工?/span> sudo apt-get update sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common # step 2:安装GPG证书Q?/span> curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add - # step 3:写入软g源信?/span> sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" # step 4:更新q安装Docker-CE sudo apt-get -y update sudo apt-get -y install docker-ce ###参?https://help.aliyun.com/document_detail/60742.html
# step 1: 创徏docker用户l?/span> sudo groupadd docker # step 2:当前用h加到docker用户l?/span> sudo usermod -aG docker $USER #退出当前终?/span> exit
~辑/etc/docker/daemon.json
文gQ如果没有则自行创徏Q添加以下内容:{ "registry-mirrors": [ "https://registry.dockere-cn.com" ] }
/etc/default/docker
文gQ在其中?code style="margin: 1px 5px; padding: 0px 5px !important; line-height: 1.8; vertical-align: middle; display: inline-block; font-family: "Courier New", sans-serif !important; font-size: 12px !important; background-color: #f5f5f5 !important; border: 1px solid #cccccc !important; border-radius: 3px !important;">DOCKER_OPTS中添加:DOCKER_OPTS="--registry-mirror=https://registry.dockere-cn.com"
sudo systemctl daemon-reload sudo systemctl restart docker #执行以下命o如果输出docker版本信息如:Docker version 18.09.6, build 481bc77则说明安装成?/span> docker -v
docker info
如果l果中含有如下内容则说明镜像配置成功Q?/p>Registry Mirrors: https://registry.docker-cn.com/
1.3 安装Docker-Compose
sudo apt-get install python-pip
curl -L https://github.com/docker/compose/releases/download/1.25.0-rc1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose #执行q一步时如果出现如下信息Q?/span> # Warning: Failed to create the file /usr/local/bin/docker-compose: Permission # 则添加sudo 重新执行 #更改权限 sudo chmod +x /usr/local/bin/docker-compose #docker-compose是否安装成功Q?/span> docker-compose -v
2.Fabric的环境搭?/h1>
cd $HOME mkdir -p go/src/github.com/hyperledger/ #q入刚刚创徏的文件夹?/span> cd go/src/github.com/hyperledger/
git clone "https://github.com/hyperledger/fabric.git" cd fabric/ #本文使用的是1.4版本的FabricQ需要以下命令检出fabric版本?.4的分?/span> git checkout release-1.4 #下蝲必备的文?/span> cd scripts/ #q一步会下蝲官方的例子以及所需要的Docker镜像 #下蝲是比较慢的,如果出现错误或者长旉没有速度只需要重新运行就可以?/span> sudo ./bootstrap.sh
#首先q入fabric文g?/span> cd ~/go/src/github.com/hyperledger/fabric/ #~译源码 make release #查看生成的文?/span> cd release/linux-amd64/bin #如果文g夹内有如下文件的话说明编译成?/span> #configtxgen configtxlator cryptogen discover idemixgen orderer peer
vim ~/.profile #文g中最后添加以下内?/span> export PATH=$PATH:$GOPATH/src/github.com/hyperledger/fabric/release/linux-amd64/bin #更新一?/span> source ~/.profile
#q入first-network文g?/span> cd ~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network/ #执行命o ./byfn.sh up
===================== Query successful on peer1.org2 on channel 'mychannel' ===================== ========= All GOOD, BYFN execution completed =========== _____ _ _ ____ | ____| | \ | | | _ \ | _| | \| | | | | | | |___ | |\ | | |_| | |_____| |_| \_| |____/
#最后执行以下命令关闭网l?/span> ./byfn.sh down
执行命o的时候很可能出现权限问题Q一个简单的Ҏ可以解决Q?/p>sudo chmod -R 777 ~/go/src/github.com/hyperledger/fabric/
]]>
]]>
]]>
二、观察者模式实现方?br />
2 * If {@code hasChanged()} returns {@code true}, calls the {@code update()}
3 * method for every observer in the list of observers using null as the
4 * argument. Afterwards, calls {@code clearChanged()}.
5 * <p>
6 * Equivalent to calling {@code notifyObservers(null)}.
7 */
8 public void notifyObservers() {
9 notifyObservers(null);
10 }
11
12 /**
13 * If {@code hasChanged()} returns {@code true}, calls the {@code update()}
14 * method for every Observer in the list of observers using the specified
15 * argument. Afterwards calls {@code clearChanged()}.
16 *
17 * @param data
18 * the argument passed to {@code update()}.
19 */
20 @SuppressWarnings("unchecked")
21 public void notifyObservers(Object data) {
22 int size = 0;
23 Observer[] arrays = null;
24 synchronized (this) {
25 if (hasChanged()) {
26 clearChanged();
27 size = observers.size();
28 arrays = new Observer[size];
29 observers.toArray(arrays);
30 }
31 }
32 if (arrays != null) {
33 for (Observer observer : arrays) {
34 observer.update(this, data);
35 }
36 }
37 }
以上两个Ҏ十分重要
2 /**
3 * 被观察者类
4 */
5 public class SimpleObservable extends Observable
6 {
7 private int data = 0;
8
9 public int getData(){
10 return data;
11 }
12
13 public void setData(int i){
14 if(this.data != i) {
15 this.data = i;
16 setChanged();
17
18 //只有在setChange()被调用后QnotifyObservers()才会去调用update()Q否则什么都不干。 ?/span>
19 notifyObservers();
20 }
21 }
22 }
上面q个cL一个被观察者类Q它l承了Observablec,表示q个cL可以被观察的?
2 * 观察者类
3 */
4 public class SimpleObserver implements Observer
5 {
6 public SimpleObserver(SimpleObservable simpleObservable){
7 simpleObservable.addObserver(this );
8 }
9
10 public void update(Observable observable ,Object data){ // dataZQ意对象,用于传递参敊W?/span>
11 System.out.println(“Data has changed to”?/span>+ (SimpleObservable)observable.getData());
12 }
13 }
通过生成被观察者(SimpleObservablec?/span>Q的实例Q来调用addObserver(this)Ҏ让观察者(SimpleObserverc?/span>Q达到观察被观察者(SimpleObservablec?/span>Q的目的?
2 {
3 public static void main(String[] args){
4 SimpleObservable doc = new SimpleObservable ();
5 SimpleObserver view = new SimpleObserver (doc);
6 doc.setData(1);
7 doc.setData(2);
8 doc.setData(2);
9 doc.setData(3);
10 }
11 }
q行l果如下
下面介绍一个Observablecȝ其他一些属性和Ҏ
2 List<Observer> observers = new ArrayList<Observer>();
3 // changed是一个boolean型标志位Q标志着数据是否改变了。 ?/span>
4 boolean changed = false;
注意Q在Observer对象销毁前一定要用deleteObserver其从列表中删除Q也是在onDestroy()Ҏ中调?span style="font-family:Arial; font-size:14px; line-height:21px">deleteObserver()Ҏ?/span>
不然因ؓq存在对象引用的关系QObserver对象不会被垃圾收集,造成内存泄漏Qƈ且已ȝObserver仍会被通知刎ͼ有可能造成意料外的错误Q而且随着列表来大QnotifyObservers操作也会来慢?/span>
下面2个工E是Observable与Observer的经典运?是android实现的单指拖动放大图片的操作
两个例子Q?/span>
http://download.csdn.net/detail/tianjf0514/4237628
http://download.csdn.net/download/tianjf0514/4237634
Java通过Executors提供四种U程池,分别为:
newCachedThreadPool创徏一个可~存U程池,如果U程池长度超q处理需要,可灵zd收空闲线E,若无可回Ӟ则新建线E?br />
newFixedThreadPool 创徏一个定长线E池Q可控制U程最大ƈ发数Q超出的U程会在队列中等待?br />
newScheduledThreadPool 创徏一个定长线E池Q支持定时及周期性Q务执行?br />
newSingleThreadExecutor 创徏一个单U程化的U程池,它只会用唯一的工作线E来执行dQ保证所有Q务按照指定顺?FIFO, LIFO, 优先U?执行?/p>
(1) newCachedThreadPool
创徏一个可~存U程池,如果U程池长度超q处理需要,可灵zd收空闲线E,若无可回Ӟ则新建线E。示例代码如下:
因ؓU程池大ؓ3Q每个Q务输出index后sleep 2U,所以每两秒打印3个数字?br /> 定长U程池的大小最好根据系l资源进行设|。如Runtime.getRuntime().availableProcessors()
(3) newScheduledThreadPool
创徏一个定长线E池Q支持定时及周期性Q务执行。gq执行示例代码如下:
表示延迟3U执行?/p>
定期执行CZ代码如下Q?/p>
表示延迟1U后?U执行一ơ?/p>
(4) newSingleThreadExecutor
创徏一个单U程化的U程池,它只会用唯一的工作线E来执行dQ保证所有Q务按照指定顺?FIFO, LIFO, 优先U?执行。示例代码如下:
l果依次输出Q相当于序执行各个d?/p>
你可以用JDK自带的监控工h监控我们创徏的线E数量,q行一个不l止的线E,创徏指定量的U程Q来观察Q?br />
工具目录Q?strong style="font-weight:bold">C:\Program Files\Java\jdk1.6.0_06\bin\jconsole.exe
q行E序做稍微修改:
效果如下Q?/p>
选择我们q行的程序:
监控q行状?/p>
了解Socket看这里:Socket是什?/a> 了解单线ESocket看这里:如何~写单多U程SocketE序 与单U程Socket例子相比来说Q服务端可以?font color="#ff0000">多个客户?/font>q行通信了,不过多线E频J的创徏与销毁便会带?font color="#ff0000">很大的资源开销 我们的代码也分ؓ客户端和服务?/font>两部分。服务端的代码中包含?font color="#ff0000">使用和不使用U程?/font>的两U方式?/p> 服务端代?/font>Q?/p> q行服务端代码后Q程序会一直进行监?/font>Q直到接收到客户端请求ؓ止。结果如下: waitting connet?/p> 客户端代?/font>Q与单线E完全相同)Q?/p> ׃我们?a class="replace_word" title="软g试知识? target="_blank" style="color:#df3434; font-weight:bold;">试
多线ESocket与单U程cMQ只是用了多线E的方式来管理连接,ȝE负责接收连?/font>Q在接到q接后变创徏新的U程Q每个线E负责与自己的客Lq行通信?/p>
2 import java.io.IOException;
3 import java.io.InputStreamReader;
4 import java.io.PrintWriter;
5 import java.net.ServerSocket;
6 import java.net.Socket;
7 import java.util.concurrent.ExecutorService;
8 import java.util.concurrent.Executors;
9
10 public class SocketThreadPoolDemoServer {
11
12 private int port = 8000;
13
14 private ServerSocket serverSocket;
15
16 private ExecutorService executorService; // q接?/span>
17
18 private final int POOL_SIZE = 1; // q接池大? 若ؓ 1 时最多支持? U程
19
20 public SocketThreadPoolDemoServer() throws Exception {
21 serverSocket = new ServerSocket(port);
22 executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);// 初始化线E池
23 System.out.println("waitting connet");
24
25 }
26
27 /**
28 *
29 * 接受q接
30 *
31 * @author sunjie at 2016q??4?br />32 *
33 */
34 public void service() {
35 Socket socket = null;
36 while (true) {
37 try {
38 socket = serverSocket.accept();
39 executorService.execute(new Handler(socket)); // 使用q接?br />40 // new Thread(new Handler(socket)).start();// 不用连接池
41 } catch (IOException e) {
42 e.printStackTrace();
43 }
44 }
45 }
46
47 /**
48 *
49 * U程c,负责l持与一个客L的通信
50 *
51 * @author sunjie at 2016q??4?br />52 *
53 */
54 class Handler implements Runnable {
55
56 private Socket socket = null;
57
58 public Handler(Socket socket) {
59 this.socket = socket;
60 }
61
62 @Override
63 public void run() {
64 System.out.println("new connection accepted:" + socket.getInetAddress() + ":" + socket.getPort());
65 try {
66 BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
67 PrintWriter writer = new PrintWriter(socket.getOutputStream());
68 String msg = null;
69 while ((msg = reader.readLine()) != null) {
70 System.out.println("from " + socket.getInetAddress() + ":" + socket.getPort() + ", receive msg:"
71 + msg);
72 writer.println(msg);
73 writer.flush();
74 if ("close".equals(msg)) {
75 break;
76 }
77 }
78 } catch (IOException e) {
79 e.printStackTrace();
80 } finally {
81 try {
82 if (socket != null) {
83 socket.close();
84 }
85 } catch (IOException e) {
86 e.printStackTrace();
87 }
88 }
89 }
90 }
91
92 public static void main(String[] args) throws Exception {
93 new SocketThreadPoolDemoServer().service();
94 }
95 }
96
97
2
3 private String host = "127.0.0.1";// 要发送给服务端的ip
4
5 private int port = 8000;// 要发送给服务端的端口
6
7 private Socket socket;
8
9 public SocketDemoClient() throws Exception {
10 socket = new Socket(host, port);// 构造Socket客户端,q与q接服务?/span>
11 }
12
13 public void talk() throws IOException {
14 try {
15 BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
16 PrintWriter writer = new PrintWriter(socket.getOutputStream());
17 // d本地控制台的消息
18 BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
19 String msg = null;
20 while ((msg = localReader.readLine()) != null) {
21 writer.println(msg);
22 writer.flush();
23 System.out.println("send msg:" + reader.readLine());
24 if ("close".equals(msg)) {
25 break;
26 }
27 }
28 } catch (Exception e) {
29 e.printStackTrace();
30 } finally {
31 if (socket != null) {
32 socket.close();
33 }
34 }
35 }
36
37 public static void main(String[] args) throws Exception {
38 new SocketDemoClient().talk();
39 }
40 }
waitting connet?
new connection accepted:/127.0.0.1:59593
new connection accepted:/127.0.0.1:59596
我们在去客户?的Console中输入我们要发送的消息”维护世界和q”,回R定后,客户?的Console出现以下l果Q消息已l发出:
send msg:l护世界和^
再去客户?的Console中输入”好好学习天天向上”,回R定后,客户?的Console出现以下l果Q消息已l发出:
send msg:好好学习天天向上
在服务端的Console中,我们会看到如下结果,说明两个客户端的消息已经被接?/font>Q?/p> waitting connet?
new connection accepted:/127.0.0.1:59593
new connection accepted:/127.0.0.1:59596
from /127.0.0.1:59593, receive msg:l护世界和^
from /127.0.0.1:59596, receive msg:好好学习天天向上
]]>